Source code of Windows XP (NT5)
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.

1963 lines
53 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: express.cxx
  7. //
  8. // Contents: Used to parse and evaluate IF expressions
  9. //
  10. // History: 96/Jan/3 DwightKr Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. // Copied from propvar.h
  16. #define BSTRLEN(bstrVal) *((ULONG *) bstrVal - 1)
  17. //+---------------------------------------------------------------------------
  18. //
  19. // Function: IsEmpty (DBCS version), private
  20. //
  21. // Arguments: [pszVal] -- string to search
  22. // [cc] -- size (in chars) of string
  23. //
  24. // Returns; TRUE if string is empty (all chars in string space-like things)
  25. //
  26. // History: 28-Jun-96 KyleP created
  27. //
  28. //----------------------------------------------------------------------------
  29. BOOL IsEmpty( char const * pszVal, unsigned cc )
  30. {
  31. //
  32. // Optimize for the common case: non-empty strings
  33. //
  34. WORD aCharType[10];
  35. unsigned ccProcessed = 0;
  36. while ( ccProcessed < cc )
  37. {
  38. unsigned ccThisPass = (unsigned)min( sizeof(aCharType)/sizeof(aCharType[0]),
  39. cc - ccProcessed );
  40. if ( !GetStringTypeExA( LOCALE_SYSTEM_DEFAULT,
  41. CT_CTYPE1,
  42. pszVal + ccProcessed,
  43. ccThisPass,
  44. aCharType ) )
  45. {
  46. ciGibDebugOut(( DEB_ERROR, "Error %d from GetStringTypeExA\n", GetLastError() ));
  47. return FALSE;
  48. }
  49. for ( unsigned i = 0; i < ccThisPass; i++ )
  50. {
  51. if ( (aCharType[i] & (C1_SPACE | C1_CNTRL | C1_BLANK)) == 0 )
  52. return FALSE;
  53. }
  54. ccProcessed += ccThisPass;
  55. }
  56. return TRUE;
  57. }
  58. //+---------------------------------------------------------------------------
  59. //
  60. // Function: IsEmpty (UniCode version), private
  61. //
  62. // Arguments: [pwszVal] -- string to search
  63. // [cc] -- size (in chars) of string
  64. //
  65. // Returns; TRUE if string is empty (all chars in string space-like things)
  66. //
  67. // History: 28-Jun-96 KyleP created
  68. //
  69. //----------------------------------------------------------------------------
  70. BOOL IsEmpty( WCHAR const * pwszVal, unsigned cc )
  71. {
  72. //
  73. // Optimize for the common case: non-empty strings
  74. //
  75. WORD aCharType[10];
  76. unsigned ccProcessed = 0;
  77. while ( ccProcessed < cc )
  78. {
  79. unsigned ccThisPass = (unsigned)min( sizeof(aCharType)/sizeof(aCharType[0]),
  80. cc - ccProcessed );
  81. //
  82. // NOTE: the unicode version of GetStringTypeEx ignores the locale
  83. //
  84. if ( !GetStringTypeExW( LOCALE_SYSTEM_DEFAULT,
  85. CT_CTYPE1,
  86. pwszVal + ccProcessed,
  87. ccThisPass,
  88. aCharType ) )
  89. {
  90. ciGibDebugOut(( DEB_ERROR, "Error %d from GetStringTypeExA\n", GetLastError() ));
  91. return FALSE;
  92. }
  93. for ( unsigned i = 0; i < ccThisPass; i++ )
  94. {
  95. if ( (aCharType[i] & (C1_SPACE | C1_CNTRL | C1_BLANK)) == 0 )
  96. return FALSE;
  97. }
  98. ccProcessed += ccThisPass;
  99. }
  100. return TRUE;
  101. }
  102. //+---------------------------------------------------------------------------
  103. //
  104. // Function: StringToSystemTime
  105. //
  106. // Synopsis: Read a SystemTime from a string
  107. //
  108. // Arguments: [wcsSystemTime] - system time to parse
  109. // [stUTC] - resulting system time
  110. //
  111. // Returns TRUE if the coearcion was possible, FALSE otherwise.
  112. //
  113. // History: 96/Jun/27 DwightKr created
  114. //
  115. //----------------------------------------------------------------------------
  116. static BOOL StringToSystemTime( WCHAR const * wcsSystemTime,
  117. SYSTEMTIME & stUTC )
  118. {
  119. if ( 0 == wcsSystemTime )
  120. {
  121. return FALSE;
  122. }
  123. stUTC.wHour = 0;
  124. stUTC.wMinute = 0;
  125. stUTC.wSecond = 0;
  126. stUTC.wMilliseconds = 0;
  127. int cItems = swscanf( wcsSystemTime,
  128. L"%4hd/%2hd/%2hd %2hd:%2hd:%2hd:%3hd",
  129. &stUTC.wYear,
  130. &stUTC.wMonth,
  131. &stUTC.wDay,
  132. &stUTC.wHour,
  133. &stUTC.wMinute,
  134. &stUTC.wSecond,
  135. &stUTC.wMilliseconds );
  136. return (cItems >= 3);
  137. }
  138. //+---------------------------------------------------------------------------
  139. //
  140. // Function: StringToFileTime
  141. //
  142. // Synopsis: Read a FileTime from a string
  143. //
  144. // Arguments: [wcsSystemTime] - system time to parse
  145. // [filetime] - resulting file time
  146. //
  147. // Returns TRUE if the coearcion was possible, FALSE otherwise.
  148. //
  149. // History: 96/Jun/27 DwightKr created
  150. //
  151. //----------------------------------------------------------------------------
  152. static BOOL StringToFileTime( WCHAR const * wcsSystemTime,
  153. FILETIME & fileTime )
  154. {
  155. SYSTEMTIME stUTC;
  156. if ( !StringToSystemTime( wcsSystemTime, stUTC ) )
  157. {
  158. return FALSE;
  159. }
  160. return SystemTimeToFileTime( &stUTC, &fileTime );
  161. }
  162. //+---------------------------------------------------------------------------
  163. //
  164. // Function: VectorCoerce
  165. //
  166. // Synopsis: Coerce's the type of a vector
  167. //
  168. // Arguments: [Value] - value to coerce
  169. // [type] - final type desired
  170. //
  171. // Returns TRUE if the coearcion was possible, FALSE otherwise.
  172. //
  173. // History: 96/Jun/27 DwightKr created
  174. //
  175. //----------------------------------------------------------------------------
  176. static BOOL VectorCoerce( CHTXIfExpressionValue & Value,
  177. VARTYPE type,
  178. PROPVARIANT & propVariant )
  179. {
  180. ULONG size = Value.GetValue()->cal.cElems;
  181. _int64 i64Value;
  182. unsigned _int64 ui64Value;
  183. double dblValue;
  184. switch (type)
  185. {
  186. case VT_LPSTR | VT_VECTOR:
  187. {
  188. XCoMem<PCHAR> aStr( size );
  189. for (unsigned i=0; i<size; i++)
  190. {
  191. XCoMem<CHAR> pszStringValue;
  192. if ( !Value.GetVectorValueStr(i, pszStringValue ) )
  193. {
  194. return FALSE;
  195. }
  196. aStr[i] = pszStringValue.Acquire();
  197. }
  198. propVariant.calpstr.cElems = size;
  199. propVariant.calpstr.pElems = (PCHAR *) aStr.Acquire();
  200. }
  201. break;
  202. case VT_LPWSTR | VT_VECTOR:
  203. {
  204. XCoMem<PWCHAR> aWStr( size );
  205. for (unsigned i=0; i<size; i++)
  206. {
  207. XCoMem<WCHAR> wszStringValue;
  208. if ( !Value.GetVectorValueWStr(i, wszStringValue) )
  209. {
  210. return FALSE;
  211. }
  212. aWStr[i] = wszStringValue.Acquire();
  213. }
  214. propVariant.calpwstr.cElems = size;
  215. propVariant.calpwstr.pElems = aWStr.Acquire();
  216. }
  217. break;
  218. case VT_BSTR | VT_VECTOR:
  219. {
  220. XCoMem<BSTR> aBStr( size );
  221. for (unsigned i=0; i<size; i++)
  222. {
  223. BSTR bwszStringValue;
  224. if ( !Value.GetVectorValueBStr(i, bwszStringValue) )
  225. {
  226. return FALSE;
  227. }
  228. aBStr[i] = bwszStringValue;
  229. }
  230. propVariant.cabstr.cElems = size;
  231. propVariant.cabstr.pElems = aBStr.Acquire();
  232. }
  233. break;
  234. case VT_UI1 | VT_VECTOR:
  235. {
  236. XCoMem<BYTE> aUI1( size );
  237. for (unsigned i=0; i<size; i++)
  238. {
  239. if ( !Value.GetVectorValueUnsignedInteger(i, ui64Value) ||
  240. ui64Value > UCHAR_MAX )
  241. {
  242. return FALSE;
  243. }
  244. aUI1[i] = (BYTE) ui64Value;
  245. }
  246. propVariant.caub.cElems = size;
  247. propVariant.caub.pElems = aUI1.Acquire();
  248. }
  249. break;
  250. case VT_I1 | VT_VECTOR:
  251. {
  252. XCoMem<BYTE> aI1( size );
  253. for (unsigned i=0; i<size; i++)
  254. {
  255. if ( !Value.GetVectorValueInteger(i, i64Value) ||
  256. (i64Value < SCHAR_MIN) || (i64Value > SCHAR_MAX) )
  257. {
  258. return FALSE;
  259. }
  260. aI1[i] = (BYTE) i64Value;
  261. }
  262. propVariant.caub.cElems = size;
  263. propVariant.caub.pElems = aI1.Acquire();
  264. }
  265. break;
  266. case VT_UI2 | VT_VECTOR:
  267. {
  268. XCoMem<USHORT> aUI2( size );
  269. for (unsigned i=0; i<size; i++)
  270. {
  271. if ( !Value.GetVectorValueUnsignedInteger(i, ui64Value) ||
  272. (ui64Value > USHRT_MAX) )
  273. {
  274. return FALSE;
  275. }
  276. aUI2[i] = (USHORT) ui64Value;
  277. }
  278. propVariant.caui.cElems = size;
  279. propVariant.caui.pElems = (USHORT *) aUI2.Acquire();
  280. }
  281. break;
  282. case VT_I2 | VT_VECTOR:
  283. {
  284. XCoMem<SHORT> aI2( size );
  285. for (unsigned i=0; i<size; i++)
  286. {
  287. if ( !Value.GetVectorValueInteger(i, i64Value) ||
  288. (i64Value < SHRT_MIN)|| (i64Value > SHRT_MAX) )
  289. {
  290. return FALSE;
  291. }
  292. aI2[i] = (SHORT) i64Value;
  293. }
  294. propVariant.cai.cElems = size;
  295. propVariant.cai.pElems = aI2.Acquire();
  296. }
  297. break;
  298. case VT_UI4 | VT_VECTOR:
  299. {
  300. XCoMem<ULONG> aUI4( size );
  301. for (unsigned i=0; i<size; i++)
  302. {
  303. if ( !Value.GetVectorValueUnsignedInteger(i, ui64Value) ||
  304. (ui64Value > ULONG_MAX) )
  305. {
  306. return FALSE;
  307. }
  308. aUI4[i] = (ULONG) ui64Value;
  309. }
  310. propVariant.caul.cElems = size;
  311. propVariant.caul.pElems = aUI4.Acquire();
  312. }
  313. break;
  314. case VT_I4 | VT_VECTOR:
  315. {
  316. XCoMem<LONG> aI4( size );
  317. for (unsigned i=0; i<size; i++)
  318. {
  319. if ( !Value.GetVectorValueInteger(i, i64Value) ||
  320. (i64Value < LONG_MIN) || (i64Value > LONG_MAX) )
  321. {
  322. return FALSE;
  323. }
  324. aI4[i] = (LONG) i64Value;
  325. }
  326. propVariant.cal.cElems = size;
  327. propVariant.cal.pElems = aI4.Acquire();
  328. }
  329. break;
  330. case VT_UI8 | VT_VECTOR:
  331. case VT_I8 | VT_VECTOR:
  332. {
  333. //
  334. // hVal used instead of uhVal because latter coercion
  335. // is not yet supported by x86 compiler.
  336. //
  337. XCoMem<LARGE_INTEGER> aUI8( size );
  338. for (unsigned i=0; i<size; i++)
  339. {
  340. if ( !Value.GetVectorValueInteger(i, i64Value) )
  341. {
  342. return FALSE;
  343. }
  344. aUI8[i].QuadPart = i64Value;
  345. }
  346. propVariant.cah.cElems = size;
  347. propVariant.cah.pElems = aUI8.Acquire();
  348. }
  349. break;
  350. case VT_R4 | VT_VECTOR:
  351. {
  352. XCoMem<float> aR4( size );
  353. for (unsigned i=0; i<size; i++)
  354. {
  355. if ( !Value.GetVectorValueDouble(i, dblValue) ||
  356. (dblValue < -FLT_MAX) || (dblValue > FLT_MAX) )
  357. {
  358. return FALSE;
  359. }
  360. aR4[i] = (float) dblValue;
  361. }
  362. propVariant.caflt.cElems = size;
  363. propVariant.caflt.pElems = aR4.Acquire();
  364. }
  365. break;
  366. case VT_R8 | VT_VECTOR:
  367. {
  368. XCoMem<double> aR8( size );
  369. for (unsigned i=0; i<size; i++)
  370. {
  371. if ( !Value.GetVectorValueDouble(i, dblValue) )
  372. {
  373. return FALSE;
  374. }
  375. aR8[i] = (double) dblValue;
  376. }
  377. propVariant.cadbl.cElems = size;
  378. propVariant.cadbl.pElems = aR8.Acquire();
  379. }
  380. break;
  381. case VT_BOOL | VT_VECTOR:
  382. {
  383. XCoMem<VARIANT_BOOL> aBOOL( size );
  384. for (unsigned i=0; i<size; i++)
  385. {
  386. if ( Value.GetType() == (VT_LPWSTR | VT_VECTOR) )
  387. {
  388. if ( (_wcsicmp(Value.GetValue()->calpwstr.pElems[i], L"TRUE") == 0) ||
  389. (_wcsicmp(Value.GetValue()->calpwstr.pElems[i], L"T") == 0)
  390. )
  391. {
  392. aBOOL[i] = VARIANT_TRUE;
  393. }
  394. else if ( (_wcsicmp(Value.GetValue()->calpwstr.pElems[i], L"FALSE") == 0) ||
  395. (_wcsicmp(Value.GetValue()->calpwstr.pElems[i], L"F") == 0)
  396. )
  397. {
  398. aBOOL[i] = VARIANT_FALSE;
  399. }
  400. else
  401. {
  402. return FALSE;
  403. }
  404. }
  405. else
  406. {
  407. if ( !Value.GetVectorValueInteger(i, i64Value) )
  408. {
  409. return FALSE;
  410. }
  411. aBOOL[i] = (VARIANT_BOOL) i64Value != VARIANT_FALSE;
  412. }
  413. }
  414. propVariant.cabool.cElems = size;
  415. propVariant.cabool.pElems = aBOOL.Acquire();
  416. }
  417. break;
  418. case VT_DATE | VT_VECTOR:
  419. {
  420. //
  421. // Dates are in the format YYYY/MM/DD hh:mm:ss:ii
  422. //
  423. if ( Value.GetType() != (VT_LPWSTR | VT_VECTOR) )
  424. {
  425. return FALSE;
  426. }
  427. XCoMem<DATE> aDate( size );
  428. for (unsigned i=0; i<size; i++)
  429. {
  430. SYSTEMTIME stUTC;
  431. if ( !StringToSystemTime( Value.GetValue()->calpwstr.pElems[i],
  432. stUTC )
  433. )
  434. {
  435. return FALSE;
  436. }
  437. if ( !SystemTimeToVariantTime( &stUTC, &aDate[i] ) )
  438. {
  439. return FALSE;
  440. }
  441. }
  442. propVariant.cadate.cElems = size;
  443. propVariant.cadate.pElems = aDate.Acquire();
  444. }
  445. break;
  446. case VT_FILETIME | VT_VECTOR:
  447. {
  448. //
  449. // FileTimes are in the format YYYY/MM/DD hh:mm:ss:ii
  450. //
  451. if ( Value.GetType() != (VT_LPWSTR | VT_VECTOR) )
  452. {
  453. return FALSE;
  454. }
  455. XCoMem<FILETIME> aFileTime( size );
  456. for (unsigned i=0; i<size; i++)
  457. {
  458. SYSTEMTIME stUTC;
  459. if ( !StringToFileTime( Value.GetValue()->calpwstr.pElems[i],
  460. aFileTime[i] )
  461. )
  462. {
  463. return FALSE;
  464. }
  465. }
  466. propVariant.cafiletime.cElems = size;
  467. propVariant.cafiletime.pElems = aFileTime.Acquire();
  468. }
  469. break;
  470. case VT_CY | VT_VECTOR:
  471. {
  472. XCoMem<CY> acy( size );
  473. for (unsigned i=0; i<size; i++)
  474. {
  475. if ( !Value.GetVectorValueDouble(i, dblValue) )
  476. {
  477. return FALSE;
  478. }
  479. VarCyFromR8( dblValue, &acy[i] );
  480. }
  481. propVariant.cacy.cElems = size;
  482. propVariant.cacy.pElems = acy.Acquire();
  483. }
  484. break;
  485. default:
  486. return FALSE;
  487. break;
  488. }
  489. propVariant.vt = type;
  490. return TRUE;
  491. }
  492. //+---------------------------------------------------------------------------
  493. //
  494. // Function: wcsistr
  495. //
  496. // Synopsis: A case-insensitive, WCHAR implemtation or strstr.
  497. //
  498. // Arguments: [wcsString] - string to search
  499. // [wcsPattern] - pattern to look for
  500. //
  501. // Returns; pointer to pattern, 0 if no match found.
  502. //
  503. // History: 96/Mar/12 DwightKr created
  504. //
  505. //----------------------------------------------------------------------------
  506. static WCHAR const * wcsistr( WCHAR const * wcsString, WCHAR const * wcsPattern )
  507. {
  508. if ( (wcsPattern == 0) || (*wcsPattern == 0) )
  509. {
  510. return wcsString;
  511. }
  512. ULONG cwcPattern = wcslen(wcsPattern);
  513. while ( *wcsString != 0 )
  514. {
  515. while ( (*wcsString != 0) &&
  516. (towupper(*wcsString) != towupper(*wcsPattern))
  517. )
  518. {
  519. wcsString++;
  520. }
  521. if ( 0 == *wcsString )
  522. {
  523. return 0;
  524. }
  525. if ( _wcsnicmp( wcsString, wcsPattern, cwcPattern) == 0 )
  526. {
  527. return wcsString;
  528. }
  529. wcsString++;
  530. }
  531. return 0;
  532. }
  533. //+---------------------------------------------------------------------------
  534. //
  535. // Function: GetDoubleFromVariant - static
  536. //
  537. // Synopsis: Converts a numerical value in a variant to a double.
  538. //
  539. // History: 96/Jan/03 DwightKr created
  540. //
  541. //----------------------------------------------------------------------------
  542. static double GetDoubleFromVariant( PROPVARIANT * pVariant )
  543. {
  544. switch (pVariant->vt)
  545. {
  546. case VT_UI1:
  547. return (double)pVariant->bVal;
  548. break;
  549. case VT_I1:
  550. return (double)(char)pVariant->bVal;
  551. break;
  552. case VT_UI2:
  553. return (double)pVariant->uiVal;
  554. break;
  555. case VT_I2:
  556. return (double)pVariant->iVal;
  557. break;
  558. case VT_UI4:
  559. case VT_UINT:
  560. return (double)pVariant->ulVal;
  561. break;
  562. case VT_I4:
  563. case VT_INT:
  564. case VT_ERROR:
  565. return (double)pVariant->lVal;
  566. break;
  567. case VT_UI8:
  568. //
  569. // hVal used instead of uhVal because latter coercion
  570. // is not yet supported by x86 compiler.
  571. //
  572. return (double)pVariant->hVal.QuadPart;
  573. break;
  574. case VT_I8:
  575. return (double) pVariant->hVal.QuadPart;
  576. break;
  577. case VT_R4:
  578. return (double)pVariant->fltVal;
  579. break;
  580. case VT_R8:
  581. return pVariant->dblVal;
  582. break;
  583. case VT_BOOL:
  584. return (double)( VARIANT_FALSE != pVariant->boolVal );
  585. break;
  586. case VT_DATE:
  587. return (double) pVariant->date;
  588. break;
  589. case VT_CY:
  590. {
  591. double dblValue;
  592. VarR8FromCy( pVariant->cyVal, &dblValue );
  593. return dblValue;
  594. }
  595. case VT_DECIMAL:
  596. {
  597. double dblValue;
  598. VarR8FromDec( & pVariant->decVal, &dblValue );
  599. return dblValue;
  600. }
  601. break;
  602. default:
  603. Win4Assert( !"VT_TYPE not supported in GetDoubleFromVariant" );
  604. break;
  605. }
  606. return 0.0;
  607. }
  608. //+---------------------------------------------------------------------------
  609. //
  610. // Function: GetI64FromVariant - static
  611. //
  612. // Synopsis: Converts a numerical value in a variant to a _int64
  613. //
  614. // History: 96/Jan/03 DwightKr created
  615. //
  616. //----------------------------------------------------------------------------
  617. static _int64 GetI64FromVariant( PROPVARIANT * pVariant )
  618. {
  619. switch (pVariant->vt)
  620. {
  621. case VT_UI1:
  622. return (_int64)pVariant->bVal;
  623. break;
  624. case VT_I1:
  625. return (_int64)pVariant->bVal;
  626. break;
  627. case VT_UI2:
  628. return (_int64)pVariant->uiVal;
  629. break;
  630. case VT_I2:
  631. return (_int64)pVariant->iVal;
  632. break;
  633. case VT_UI4:
  634. case VT_UINT:
  635. return (_int64)pVariant->ulVal;
  636. break;
  637. case VT_I4:
  638. case VT_INT:
  639. case VT_ERROR:
  640. return (_int64)pVariant->lVal;
  641. break;
  642. case VT_UI8:
  643. return (_int64)pVariant->uhVal.QuadPart;
  644. break;
  645. case VT_I8:
  646. return pVariant->hVal.QuadPart;
  647. break;
  648. case VT_R4:
  649. Win4Assert( !"VT_R4 not supported in GetI64FromVariant, use GetDoubleFromVariant" );
  650. break;
  651. case VT_R8:
  652. Win4Assert( !"VT_R8 not supported in GetI64FromVariant, use GetDoubleFromVariant" );
  653. break;
  654. case VT_DECIMAL:
  655. Win4Assert( !"VT_DECIMAL not supported in GetI64FromVariant, use GetDoubleFromVariant" );
  656. break;
  657. case VT_DATE:
  658. {
  659. LONG lValue;
  660. VarI4FromDate( pVariant->date, & lValue );
  661. return lValue;
  662. }
  663. break;
  664. case VT_BOOL:
  665. return (_int64) ( VARIANT_FALSE != pVariant->boolVal );
  666. break;
  667. case VT_CY:
  668. {
  669. return (_int64) pVariant->cyVal.Hi;
  670. }
  671. break;
  672. default:
  673. Win4Assert( !"VT_TYPE not supported in GetI64FromVariant" );
  674. break;
  675. }
  676. return 0;
  677. }
  678. //+---------------------------------------------------------------------------
  679. //
  680. // Method: CHTXIfExpression::CHTXIfExpression - public constructor
  681. //
  682. // Synopsis: Builds a CHTXIfExpression object, and determines if
  683. // this is an IF expression.
  684. //
  685. // Arguments: [scanner] - parser containing the line to be parsed
  686. // [variableSet] - list of replaceable parameters
  687. //
  688. // History: 96/Jan/03 DwightKr created
  689. //
  690. //----------------------------------------------------------------------------
  691. CHTXIfExpression::CHTXIfExpression( CTokenizeString & scanner,
  692. CVariableSet & variableSet,
  693. COutputFormat & outputFormat ) :
  694. _scanner(scanner),
  695. _variableSet(variableSet),
  696. _outputFormat(outputFormat)
  697. {
  698. //
  699. // The first word better be an 'if'
  700. //
  701. Win4Assert ( _scanner.LookAhead() == TEXT_TOKEN );
  702. XPtrST<WCHAR> wcsIf( _scanner.AcqWord() );
  703. Win4Assert( _wcsicmp(wcsIf.GetPointer(), L"if") == 0 );
  704. _scanner.Accept(); // Skip over the "if"
  705. }
  706. //+---------------------------------------------------------------------------
  707. //
  708. // Method: CHTXIfExpression::Evaluate - public
  709. //
  710. // Synopsis: Evaluates an IF expression by breaking it up into the
  711. // left-side, operator & right-side.
  712. //
  713. // Returns: TRUE or FALSE - the evaluation of the IF expression
  714. //
  715. // History: 96/Jan/03 DwightKr created
  716. //
  717. //----------------------------------------------------------------------------
  718. BOOL CHTXIfExpression::Evaluate()
  719. {
  720. CHTXIfExpressionValue lhValue( _scanner, _variableSet, _outputFormat );
  721. lhValue.ParseValue();
  722. CHTXIfExpressionOperator ifOperator( _scanner );
  723. ifOperator.ParseOperator();
  724. if ( ifOperator.Operator() != ISEMPTY_TOKEN )
  725. {
  726. CHTXIfExpressionValue rhValue( _scanner, _variableSet, _outputFormat );
  727. rhValue.ParseValue();
  728. return ifOperator.Evaluate( lhValue, rhValue );
  729. }
  730. else
  731. {
  732. if ( _scanner.LookAhead() != EOS_TOKEN )
  733. THROW( CHTXException( MSG_CI_HTX_EXPECTING_OPERATOR, 0, 0 ) );
  734. return ifOperator.Evaluate( lhValue );
  735. }
  736. }
  737. //+---------------------------------------------------------------------------
  738. //
  739. // Method: CHTXIfExpressionValue::CHTXIfExpressionValue - public constructor
  740. //
  741. // Synopsis: Parses one half of an IF expression and determines its value
  742. //
  743. // Parameters: [scanner] - parser containing the IF to be parsed
  744. // [variableSet] - list of replaceable paremeters
  745. //
  746. // History: 96/Jan/03 DwightKr created
  747. //
  748. //----------------------------------------------------------------------------
  749. CHTXIfExpressionValue::CHTXIfExpressionValue( CTokenizeString & scanner,
  750. CVariableSet & variableSet,
  751. COutputFormat & outputFormat) :
  752. _scanner(scanner),
  753. _variableSet(variableSet),
  754. _outputFormat(outputFormat),
  755. _wcsStringValue(0),
  756. _fOwnVector(FALSE),
  757. _fIsConstant(FALSE)
  758. {
  759. }
  760. //+---------------------------------------------------------------------------
  761. //----------------------------------------------------------------------------
  762. CHTXIfExpressionValue::~CHTXIfExpressionValue()
  763. {
  764. delete _wcsStringValue;
  765. if ( _fOwnVector )
  766. {
  767. Win4Assert ( ( _propVariant.vt & VT_VECTOR ) != 0 );
  768. if ( _propVariant.vt == ( VT_LPWSTR | VT_VECTOR ) )
  769. {
  770. for (unsigned i=0; i<_propVariant.calpwstr.cElems; i++)
  771. {
  772. delete _propVariant.calpwstr.pElems[i];
  773. }
  774. }
  775. delete _propVariant.cal.pElems;
  776. }
  777. }
  778. //+---------------------------------------------------------------------------
  779. //
  780. // Method: CHTXIfExpressionValue::ParseValue - public
  781. //
  782. // Synopsis: Parses one side of an IF expression.
  783. //
  784. // History: 96/Jan/03 DwightKr created
  785. // 96/Feb/13 DwightKr add suppport for quoted strings
  786. //
  787. //----------------------------------------------------------------------------
  788. void CHTXIfExpressionValue::ParseValue()
  789. {
  790. //
  791. // The first token on this line must be a word/phrase, and not an
  792. // operator. It may be quoted.
  793. //
  794. _fIsConstant = TRUE; // Assume it is a constant, not a var
  795. if ( _scanner.LookAhead() == QUOTES_TOKEN )
  796. {
  797. _scanner.AcceptQuote(); // Skip over the opening "
  798. _propVariant.vt = VT_LPWSTR;
  799. _wcsStringValue = _scanner.AcqPhrase();
  800. _scanner.Accept(); // Skip over the string
  801. if ( _scanner.LookAhead() != QUOTES_TOKEN )
  802. {
  803. THROW( CHTXException(MSG_CI_HTX_MISSING_QUOTE, 0, 0) );
  804. }
  805. _scanner.Accept(); // Skip over the closing "
  806. }
  807. else if (_scanner.LookAhead() == C_OPEN_TOKEN )
  808. {
  809. _scanner.Accept(); // Skip over the opening {
  810. _scanner.AcqVector( _propVariant );
  811. _fOwnVector = TRUE;
  812. if ( _scanner.LookAhead() != C_CLOSE_TOKEN )
  813. {
  814. THROW( CHTXException(MSG_CI_HTX_MISSING_BRACKET, 0, 0) );
  815. }
  816. _scanner.Accept(); // Skip over the closing }
  817. }
  818. else
  819. {
  820. if ( _scanner.LookAhead() != TEXT_TOKEN )
  821. {
  822. THROW( CHTXException(QPARSE_E_UNEXPECTED_EOS, 0, 0) );
  823. }
  824. //
  825. // Determine if this is a number, or a string. If it is a string,
  826. // then look it up in the variableSet. If it's defined in the
  827. // variableSet, look up its value, and determine if this new value
  828. // is a number.
  829. //
  830. if ( _scanner.GetGUID( _guid ) )
  831. {
  832. _propVariant.vt = VT_CLSID;
  833. _propVariant.puuid = &_guid;
  834. }
  835. else if ( _scanner.GetNumber( (unsigned _int64) *((unsigned _int64 *) (&_propVariant.uhVal)) ) )
  836. {
  837. _propVariant.vt = VT_UI8;
  838. }
  839. else if ( _scanner.GetNumber( (_int64) *((_int64 *) (&_propVariant.hVal)) ) )
  840. {
  841. _propVariant.vt = VT_I8;
  842. }
  843. else if ( _scanner.GetNumber( _propVariant.dblVal ) )
  844. {
  845. _propVariant.vt = VT_R8;
  846. }
  847. else
  848. {
  849. //
  850. // Its not a number, get its value in a local buffer.
  851. //
  852. _propVariant.vt = VT_LPWSTR;
  853. XPtrST<WCHAR> wcsVariableName( _scanner.AcqWord() );
  854. //
  855. // Try to find this variable/string in the variableSet
  856. //
  857. CVariable *pVariable = _variableSet.Find( wcsVariableName.GetPointer() );
  858. if ( 0 != pVariable )
  859. {
  860. _fIsConstant = FALSE;
  861. //
  862. // We have a variable with this name. Get its string value.
  863. //
  864. ULONG cwcValue;
  865. WCHAR * wcsValue = pVariable->GetStringValueRAW(_outputFormat, cwcValue);
  866. _wcsStringValue = new WCHAR[ cwcValue + 1 ];
  867. RtlCopyMemory( _wcsStringValue,
  868. wcsValue,
  869. (cwcValue+1) * sizeof(WCHAR) );
  870. _propVariant = *pVariable->GetValue();
  871. }
  872. else
  873. {
  874. //
  875. // The variable name could not be found.
  876. //
  877. _wcsStringValue = wcsVariableName.Acquire();
  878. }
  879. }
  880. _scanner.Accept(); // Skip over the "value"
  881. }
  882. }
  883. //+---------------------------------------------------------------------------
  884. //
  885. // Method: CHTXIfExpressionValue::GetStringValue - public
  886. //
  887. // Synopsis: Returns the string value of the variable
  888. //
  889. // History: 96/Jan/03 DwightKr created
  890. //
  891. //----------------------------------------------------------------------------
  892. WCHAR * CHTXIfExpressionValue::GetStringValue()
  893. {
  894. if ( 0 == _wcsStringValue )
  895. {
  896. switch ( _propVariant.vt )
  897. {
  898. case VT_I4:
  899. _wcsStringValue = new WCHAR[20];
  900. _itow( _propVariant.ulVal, _wcsStringValue, 10 );
  901. break;
  902. case VT_UI4:
  903. _wcsStringValue = new WCHAR[20];
  904. _itow( _propVariant.lVal, _wcsStringValue, 10 );
  905. break;
  906. case VT_R8:
  907. _wcsStringValue = new WCHAR[320];
  908. swprintf( _wcsStringValue, L"%f", _propVariant.dblVal );
  909. break;
  910. default:
  911. _wcsStringValue = new WCHAR[1];
  912. _wcsStringValue[0] = 0;
  913. break;
  914. }
  915. }
  916. return _wcsStringValue;
  917. }
  918. //+---------------------------------------------------------------------------
  919. //
  920. // Method: CHTXIfExpressionOperator::CHTXIfExpressionOperator - public constructor
  921. //
  922. // Synopsis: Parses the operator in an IF expression
  923. //
  924. // Parameters: [scanner] - parser containing the operator to be parsed
  925. //
  926. // History: 96/Jan/03 DwightKr created
  927. //
  928. //----------------------------------------------------------------------------
  929. CHTXIfExpressionOperator::CHTXIfExpressionOperator( CTokenizeString & scanner ) :
  930. _scanner(scanner), _operator(EQUAL_TOKEN)
  931. {
  932. }
  933. //+---------------------------------------------------------------------------
  934. //
  935. // Method: CHTXIfExpressionOperator::ParseOperator - public
  936. //
  937. // Synopsis: Parses the operator in an IF expression
  938. //
  939. // History: 96/Jan/03 DwightKr created
  940. //
  941. //----------------------------------------------------------------------------
  942. void CHTXIfExpressionOperator::ParseOperator()
  943. {
  944. //
  945. // The first token on this line must be a word, and not an operator.
  946. // We're looking for operators such as eq, ne, gt, ...
  947. //
  948. if ( _scanner.LookAhead() != TEXT_TOKEN )
  949. {
  950. THROW( CHTXException(MSG_CI_HTX_EXPECTING_OPERATOR, 0, 0) );
  951. }
  952. XPtrST<WCHAR> wcsOperator( _scanner.AcqWord() );
  953. if ( 0 == wcsOperator.GetPointer() )
  954. THROW( CHTXException(MSG_CI_HTX_EXPECTING_OPERATOR, 0, 0) );
  955. if ( wcscmp(wcsOperator.GetPointer(), L"EQ") == 0 )
  956. {
  957. _operator = EQUAL_TOKEN;
  958. }
  959. else if ( wcscmp(wcsOperator.GetPointer(), L"NE") == 0 )
  960. {
  961. _operator = NOT_EQUAL_TOKEN;
  962. }
  963. else if ( wcscmp(wcsOperator.GetPointer(), L"GT") == 0 )
  964. {
  965. _operator = GREATER_TOKEN;
  966. }
  967. else if ( wcscmp(wcsOperator.GetPointer(), L"GE") == 0 )
  968. {
  969. _operator = GREATER_EQUAL_TOKEN;
  970. }
  971. else if ( wcscmp(wcsOperator.GetPointer(), L"LT") == 0 )
  972. {
  973. _operator = LESS_TOKEN;
  974. }
  975. else if ( wcscmp(wcsOperator.GetPointer(), L"LE") == 0 )
  976. {
  977. _operator = LESS_EQUAL_TOKEN;
  978. }
  979. else if ( wcscmp(wcsOperator.GetPointer(), L"CONTAINS") == 0 )
  980. {
  981. _operator = CONTAINS_TOKEN;
  982. }
  983. else if ( wcscmp(wcsOperator.GetPointer(), L"ISEMPTY") == 0 )
  984. {
  985. _operator = ISEMPTY_TOKEN;
  986. }
  987. else if ( wcscmp(wcsOperator.GetPointer(), L"ISTYPEEQ") == 0 )
  988. {
  989. _operator = ISTYPEEQUAL_TOKEN;
  990. }
  991. else
  992. {
  993. THROW( CHTXException(MSG_CI_HTX_EXPECTING_OPERATOR, 0, 0) );
  994. }
  995. _scanner.Accept(); // Skip over the "operator"
  996. }
  997. //+---------------------------------------------------------------------------
  998. //
  999. // Method: CHTXIfExpressionOperator::Evaluate - public
  1000. //
  1001. // Synopsis: Using the operator already obtained, it evaluates a TRUE/FALSE
  1002. // result by comparing the lhValue and the rhValue.
  1003. //
  1004. // Arguments: [lhValue] - left hand value of the IF statement
  1005. // [rhValue] - right hand value of the IF statement
  1006. //
  1007. // History: 96/Jan/03 DwightKr created
  1008. //
  1009. //----------------------------------------------------------------------------
  1010. BOOL CHTXIfExpressionOperator::Evaluate( CHTXIfExpressionValue & lhValue,
  1011. CHTXIfExpressionValue & rhValue )
  1012. {
  1013. //
  1014. // If the operator is CONTAINS_TOKEN, then we'll simply do a wcsistr
  1015. // of the string representations of the two values.
  1016. //
  1017. if ( CONTAINS_TOKEN == _operator )
  1018. {
  1019. return wcsistr(lhValue.GetStringValue(), rhValue.GetStringValue()) != 0;
  1020. }
  1021. //
  1022. // We must setup the comparision functions to examine like types.
  1023. // The type of lhValue and rhValue must be converted to like types.
  1024. // If any one of them is a string, then we'll treat both of them
  1025. // like strings.
  1026. //
  1027. PROPVARIANT lhVariant;
  1028. PROPVARIANT rhVariant;
  1029. SPropVariant xlhPropVariant;
  1030. SPropVariant xrhPropVariant;
  1031. //
  1032. // If neither one are vectors, perform the following conversions
  1033. //
  1034. if ( ((lhValue.GetType() & VT_VECTOR) == 0) &&
  1035. ((rhValue.GetType() & VT_VECTOR) == 0) )
  1036. {
  1037. if ( (lhValue.GetType() == VT_LPWSTR) ||
  1038. (rhValue.GetType() == VT_LPWSTR) ||
  1039. (lhValue.GetType() == VT_LPSTR) ||
  1040. (rhValue.GetType() == VT_LPSTR) ||
  1041. (lhValue.GetType() == VT_BSTR) ||
  1042. (rhValue.GetType() == VT_BSTR)
  1043. )
  1044. {
  1045. lhVariant.vt = VT_LPWSTR;
  1046. rhVariant.vt = VT_LPWSTR;
  1047. lhVariant.pwszVal = lhValue.GetStringValue();
  1048. rhVariant.pwszVal = rhValue.GetStringValue();
  1049. }
  1050. else if (lhValue.GetType() == rhValue.GetType() ||
  1051. lhValue.GetType() == VT_EMPTY ||
  1052. rhValue.GetType() == VT_EMPTY)
  1053. {
  1054. lhVariant = *lhValue.GetValue();
  1055. rhVariant = *rhValue.GetValue();
  1056. }
  1057. else if ( (lhValue.GetType() == VT_FILETIME) ||
  1058. (rhValue.GetType() == VT_FILETIME) )
  1059. {
  1060. if ( lhValue.GetType() == VT_LPWSTR )
  1061. {
  1062. if ( !StringToFileTime( lhValue.GetValue()->pwszVal,
  1063. lhVariant.filetime )
  1064. )
  1065. {
  1066. return FALSE;
  1067. }
  1068. lhVariant.vt = VT_FILETIME;
  1069. rhVariant = *rhValue.GetValue();
  1070. }
  1071. else if ( rhValue.GetType() == VT_LPWSTR )
  1072. {
  1073. if ( !StringToFileTime( rhValue.GetValue()->pwszVal,
  1074. rhVariant.filetime )
  1075. )
  1076. {
  1077. return FALSE;
  1078. }
  1079. rhVariant.vt = VT_FILETIME;
  1080. lhVariant = *lhValue.GetValue();
  1081. }
  1082. }
  1083. else if ( (lhValue.GetType() == VT_R4) || (lhValue.GetType() == VT_R8) ||
  1084. (rhValue.GetType() == VT_R4) || (rhValue.GetType() == VT_R8) ||
  1085. (lhValue.GetType() == VT_CY) || (rhValue.GetType() == VT_CY) ||
  1086. (lhValue.GetType() == VT_DECIMAL) || (rhValue.GetType() == VT_DECIMAL) ||
  1087. (lhValue.GetType() == VT_DATE) || (rhValue.GetType() == VT_DATE)
  1088. )
  1089. {
  1090. //
  1091. // At least one of them is a floating number. Convert them both
  1092. // to floating point.
  1093. //
  1094. lhVariant.vt = VT_R8;
  1095. rhVariant.vt = VT_R8;
  1096. lhVariant.dblVal = GetDoubleFromVariant( lhValue.GetValue() );
  1097. rhVariant.dblVal = GetDoubleFromVariant( rhValue.GetValue() );
  1098. }
  1099. else if ( (lhValue.GetType() == VT_I8) || (lhValue.GetType() == VT_I4) ||
  1100. (lhValue.GetType() == VT_I2) || (lhValue.GetType() == VT_I1) ||
  1101. (rhValue.GetType() == VT_I8) || (rhValue.GetType() == VT_I4) ||
  1102. (rhValue.GetType() == VT_I2) || (rhValue.GetType() == VT_I1) ||
  1103. (lhValue.GetType() == VT_INT) || (rhValue.GetType() == VT_INT)
  1104. )
  1105. {
  1106. lhVariant.vt = VT_I8;
  1107. rhVariant.vt = VT_I8;
  1108. lhVariant.hVal.QuadPart = GetI64FromVariant( lhValue.GetValue() );
  1109. rhVariant.hVal.QuadPart = GetI64FromVariant( rhValue.GetValue() );
  1110. }
  1111. else if ( (lhValue.GetType() == VT_UI8) || (lhValue.GetType() == VT_UI4) ||
  1112. (lhValue.GetType() == VT_UI2) || (lhValue.GetType() == VT_UI1) ||
  1113. (rhValue.GetType() == VT_UI8) || (rhValue.GetType() == VT_UI4) ||
  1114. (rhValue.GetType() == VT_UI2) || (rhValue.GetType() == VT_UI1) ||
  1115. (lhValue.GetType() == VT_UINT) || (rhValue.GetType() == VT_UINT)
  1116. )
  1117. {
  1118. lhVariant.vt = VT_UI8;
  1119. rhVariant.vt = VT_UI8;
  1120. lhVariant.uhVal.QuadPart = GetI64FromVariant( lhValue.GetValue() );
  1121. rhVariant.uhVal.QuadPart = GetI64FromVariant( rhValue.GetValue() );
  1122. }
  1123. else
  1124. {
  1125. lhVariant = *lhValue.GetValue();
  1126. rhVariant = *rhValue.GetValue();
  1127. }
  1128. }
  1129. else if ( ((lhValue.GetType() & VT_VECTOR) != 0) &&
  1130. ((rhValue.GetType() & VT_VECTOR) != 0)
  1131. )
  1132. {
  1133. //
  1134. // Both are vectors
  1135. //
  1136. //
  1137. // If the vector's are of different types, attempt to Coerce one
  1138. // type into the other.
  1139. //
  1140. if ( lhValue.GetType() != rhValue.GetType() )
  1141. {
  1142. //
  1143. // Coerce the types to be the same if possible. Attempt to
  1144. // Coerce a constant into the type of the variable, rather
  1145. // then vise versa. If this fails, attempt the opposite
  1146. // coearison.
  1147. //
  1148. if ( lhValue.IsConstant() )
  1149. {
  1150. if ( VectorCoerce( lhValue, rhValue.GetType(), lhVariant ) )
  1151. {
  1152. Win4Assert( xlhPropVariant.IsNull() );
  1153. xlhPropVariant.Set( &lhVariant );
  1154. rhVariant = *rhValue.GetValue();
  1155. }
  1156. else
  1157. {
  1158. if ( VectorCoerce( rhValue, lhValue.GetType(), rhVariant ) )
  1159. {
  1160. Win4Assert( xrhPropVariant.IsNull() );
  1161. xrhPropVariant.Set( &rhVariant );
  1162. lhVariant = *lhValue.GetValue();
  1163. }
  1164. }
  1165. }
  1166. else if ( rhValue.IsConstant() )
  1167. {
  1168. if ( VectorCoerce( rhValue, lhValue.GetType(), rhVariant ) )
  1169. {
  1170. Win4Assert( xrhPropVariant.IsNull() );
  1171. xrhPropVariant.Set( &rhVariant );
  1172. lhVariant = *lhValue.GetValue();
  1173. }
  1174. else
  1175. {
  1176. if ( VectorCoerce( lhValue, rhValue.GetType(), lhVariant ) )
  1177. {
  1178. Win4Assert( xlhPropVariant.IsNull() );
  1179. xlhPropVariant.Set( &lhVariant );
  1180. rhVariant = *rhValue.GetValue();
  1181. }
  1182. }
  1183. }
  1184. else
  1185. {
  1186. lhVariant = *lhValue.GetValue();
  1187. rhVariant = *rhValue.GetValue();
  1188. }
  1189. }
  1190. else
  1191. {
  1192. lhVariant = *lhValue.GetValue();
  1193. rhVariant = *rhValue.GetValue();
  1194. }
  1195. }
  1196. else
  1197. {
  1198. lhVariant = *lhValue.GetValue();
  1199. rhVariant = *rhValue.GetValue();
  1200. }
  1201. switch ( _operator )
  1202. {
  1203. case EQUAL_TOKEN:
  1204. return VT_VARIANT_EQ( lhVariant, rhVariant );
  1205. break;
  1206. case NOT_EQUAL_TOKEN:
  1207. return VT_VARIANT_NE( lhVariant, rhVariant );
  1208. break;
  1209. case GREATER_TOKEN:
  1210. return VT_VARIANT_GT( lhVariant, rhVariant );
  1211. break;
  1212. case GREATER_EQUAL_TOKEN:
  1213. return VT_VARIANT_GE( lhVariant, rhVariant );
  1214. break;
  1215. case LESS_TOKEN:
  1216. return VT_VARIANT_LT( lhVariant, rhVariant );
  1217. break;
  1218. case LESS_EQUAL_TOKEN:
  1219. return VT_VARIANT_LE( lhVariant, rhVariant );
  1220. break;
  1221. case ISTYPEEQUAL_TOKEN:
  1222. {
  1223. //
  1224. // Three valid cases exist:
  1225. //
  1226. // if variable IsTypeEQ constant
  1227. // if constant IsTypeEQ variable
  1228. // if variable IsTypeEQ variable
  1229. //
  1230. // Therefore, at least ONE of them must be a variable.
  1231. //
  1232. if ( lhValue.IsConstant() && rhValue.IsConstant() )
  1233. {
  1234. THROW( CHTXException(MSG_CI_HTX_ISTYPEEQUAL_WITH_CONSTANTS, 0, 0) );
  1235. }
  1236. //
  1237. // If a constant is used, then it must be of type I4. Not floating,
  1238. // guid, vector, etc.
  1239. //
  1240. if ( lhValue.IsConstant() )
  1241. {
  1242. if ( lhValue.GetType() != VT_UI4 )
  1243. {
  1244. THROW( CHTXException(MSG_CI_HTX_ISTYPEEQUAL_INVALID_CONSTANT, 0, 0) );
  1245. }
  1246. return lhValue.GetValue()->ulVal == (ULONG) rhValue.GetType();
  1247. }
  1248. else if ( rhValue.IsConstant() )
  1249. {
  1250. if ( rhValue.GetType() != VT_UI4 )
  1251. {
  1252. THROW( CHTXException(MSG_CI_HTX_ISTYPEEQUAL_INVALID_CONSTANT, 0, 0) );
  1253. }
  1254. return rhValue.GetValue()->ulVal == (ULONG) lhValue.GetType();
  1255. }
  1256. else
  1257. {
  1258. return lhValue.GetType() == rhValue.GetType();
  1259. }
  1260. }
  1261. break;
  1262. default:
  1263. Win4Assert(!"Illegal case in NON-VECTOR CExpressionOperator::Evaluate" );
  1264. return FALSE;
  1265. break;
  1266. }
  1267. return FALSE;
  1268. }
  1269. //+---------------------------------------------------------------------------
  1270. //
  1271. // Method: CHTXIfExpressionOperator::Evaluate - public
  1272. //
  1273. // Synopsis: Using the operator already obtained, it evaluates a TRUE/FALSE
  1274. // result by comparing the lhValue and the rhValue.
  1275. //
  1276. // Arguments: [lhValue] - left hand value of the IF statement
  1277. //
  1278. // History: 29-Jun-96 KyleP created
  1279. //
  1280. //----------------------------------------------------------------------------
  1281. BOOL CHTXIfExpressionOperator::Evaluate( CHTXIfExpressionValue & lhValue )
  1282. {
  1283. Win4Assert( ISEMPTY_TOKEN == _operator );
  1284. BOOL fEmpty;
  1285. ULONG vt = lhValue.GetType();
  1286. switch ( vt )
  1287. {
  1288. case VT_EMPTY:
  1289. case VT_NULL:
  1290. fEmpty = TRUE;
  1291. break;
  1292. case VT_LPSTR:
  1293. {
  1294. char const * pszVal = lhValue.GetValue()->pszVal;
  1295. unsigned cc = strlen( pszVal );
  1296. fEmpty = IsEmpty( pszVal, cc );
  1297. break;
  1298. }
  1299. case VT_LPSTR | VT_VECTOR:
  1300. {
  1301. for ( unsigned i = 0; i < lhValue.GetValue()->calpstr.cElems; i++ )
  1302. {
  1303. char const * pszVal = lhValue.GetValue()->calpstr.pElems[i];
  1304. unsigned cc = strlen( pszVal );
  1305. fEmpty = IsEmpty( pszVal, cc );
  1306. if ( !fEmpty )
  1307. break;
  1308. }
  1309. break;
  1310. }
  1311. case VT_BSTR:
  1312. {
  1313. WCHAR const * pwszVal = lhValue.GetValue()->bstrVal;
  1314. unsigned cc = BSTRLEN( lhValue.GetValue()->bstrVal );
  1315. fEmpty = IsEmpty( pwszVal, cc );
  1316. break;
  1317. }
  1318. case VT_BSTR | VT_VECTOR:
  1319. {
  1320. for ( unsigned i = 0; i < lhValue.GetValue()->cabstr.cElems; i++ )
  1321. {
  1322. WCHAR const * pwszVal = lhValue.GetValue()->cabstr.pElems[i];
  1323. unsigned cc = BSTRLEN( lhValue.GetValue()->cabstr.pElems[i] );
  1324. fEmpty = IsEmpty( pwszVal, cc );
  1325. if ( !fEmpty )
  1326. break;
  1327. }
  1328. break;
  1329. }
  1330. case VT_LPWSTR:
  1331. {
  1332. WCHAR const * pwszVal = lhValue.GetValue()->pwszVal;
  1333. unsigned cc = wcslen( pwszVal );
  1334. fEmpty = IsEmpty( pwszVal, cc );
  1335. break;
  1336. }
  1337. case VT_LPWSTR | VT_VECTOR:
  1338. {
  1339. for ( unsigned i = 0; i < lhValue.GetValue()->calpwstr.cElems; i++ )
  1340. {
  1341. WCHAR const * pwszVal = lhValue.GetValue()->calpwstr.pElems[i];
  1342. unsigned cc = wcslen( pwszVal );
  1343. fEmpty = IsEmpty( pwszVal, cc );
  1344. if ( !fEmpty )
  1345. break;
  1346. }
  1347. break;
  1348. }
  1349. default:
  1350. fEmpty = FALSE;
  1351. }
  1352. return fEmpty;
  1353. }
  1354. //+---------------------------------------------------------------------------
  1355. //
  1356. // Method: CHTXIfExpressionValue::GetVectorValueInteger, public
  1357. //
  1358. // Synopsis: Returns the _int64 value of a vector's element
  1359. //
  1360. // History: 96/Jun/27 DwightKr created
  1361. //
  1362. //----------------------------------------------------------------------------
  1363. BOOL CHTXIfExpressionValue::GetVectorValueInteger( unsigned index,
  1364. _int64 & i64Value )
  1365. {
  1366. switch ( GetType() )
  1367. {
  1368. case VT_UI1 | VT_VECTOR:
  1369. i64Value = (_int64) _propVariant.caub.pElems[index];
  1370. break;
  1371. case VT_I1 | VT_VECTOR:
  1372. i64Value = (_int64) _propVariant.caub.pElems[index];
  1373. break;
  1374. case VT_UI2 | VT_VECTOR:
  1375. i64Value = (_int64) _propVariant.caui.pElems[index];
  1376. break;
  1377. case VT_I2 | VT_VECTOR:
  1378. i64Value = (_int64) _propVariant.cai.pElems[index];
  1379. break;
  1380. case VT_UI4 | VT_VECTOR:
  1381. i64Value = (_int64) _propVariant.caul.pElems[index];
  1382. break;
  1383. case VT_I4 | VT_VECTOR:
  1384. i64Value = (_int64) _propVariant.cal.pElems[index];
  1385. break;
  1386. case VT_UI8 | VT_VECTOR:
  1387. i64Value = (_int64) _propVariant.cauh.pElems[index].QuadPart;
  1388. break;
  1389. case VT_I8 | VT_VECTOR:
  1390. i64Value = (_int64) _propVariant.cah.pElems[index].QuadPart;
  1391. break;
  1392. case VT_R4 | VT_VECTOR:
  1393. return FALSE;
  1394. break;
  1395. case VT_R8 | VT_VECTOR:
  1396. return FALSE;
  1397. break;
  1398. case VT_DATE | VT_VECTOR:
  1399. {
  1400. LONG lValue;
  1401. VarI4FromDate( _propVariant.cadate.pElems[index], &lValue );
  1402. i64Value = lValue;
  1403. }
  1404. break;
  1405. case VT_BOOL | VT_VECTOR:
  1406. i64Value = (_int64) ( VARIANT_FALSE != _propVariant.cabool.pElems[index] );
  1407. break;
  1408. case VT_CY | VT_VECTOR:
  1409. {
  1410. return FALSE;
  1411. }
  1412. break;
  1413. default:
  1414. return FALSE;
  1415. break;
  1416. }
  1417. return TRUE;
  1418. }
  1419. //+---------------------------------------------------------------------------
  1420. //
  1421. // Method: CHTXIfExpressionValue::GetVectorValueUnsignedInteger, public
  1422. //
  1423. // Synopsis: Returns the unsigned _int64 value of a vector's element
  1424. //
  1425. // History: 96/Jun/27 DwightKr created
  1426. //
  1427. //----------------------------------------------------------------------------
  1428. BOOL CHTXIfExpressionValue::GetVectorValueUnsignedInteger( unsigned index,
  1429. unsigned _int64 & ui64Value )
  1430. {
  1431. switch ( GetType() )
  1432. {
  1433. case VT_UI1 | VT_VECTOR:
  1434. ui64Value = (unsigned _int64) _propVariant.caub.pElems[index];
  1435. break;
  1436. case VT_I1 | VT_VECTOR:
  1437. ui64Value = (unsigned _int64) _propVariant.caub.pElems[index];
  1438. break;
  1439. case VT_UI2 | VT_VECTOR:
  1440. ui64Value = (unsigned _int64) _propVariant.caui.pElems[index];
  1441. break;
  1442. case VT_I2 | VT_VECTOR:
  1443. if ( _propVariant.cai.pElems[index] < 0 )
  1444. return FALSE;
  1445. ui64Value = (unsigned _int64) _propVariant.cai.pElems[index];
  1446. break;
  1447. case VT_UI4 | VT_VECTOR:
  1448. ui64Value = (unsigned _int64) _propVariant.caul.pElems[index];
  1449. break;
  1450. case VT_I4 | VT_VECTOR:
  1451. if ( _propVariant.cal.pElems[index] < 0 )
  1452. return FALSE;
  1453. ui64Value = (unsigned _int64) _propVariant.cal.pElems[index];
  1454. break;
  1455. case VT_UI8 | VT_VECTOR:
  1456. ui64Value = (unsigned _int64) _propVariant.cauh.pElems[index].QuadPart;
  1457. break;
  1458. case VT_I8 | VT_VECTOR:
  1459. if ( _propVariant.cah.pElems[index].QuadPart < 0 )
  1460. return FALSE;
  1461. ui64Value = (unsigned _int64) _propVariant.cah.pElems[index].QuadPart;
  1462. break;
  1463. case VT_R4 | VT_VECTOR:
  1464. return FALSE;
  1465. break;
  1466. case VT_R8 | VT_VECTOR:
  1467. return FALSE;
  1468. break;
  1469. case VT_BOOL | VT_VECTOR:
  1470. ui64Value = (unsigned _int64) ( VARIANT_FALSE != _propVariant.cabool.pElems[index] );
  1471. break;
  1472. case VT_CY | VT_VECTOR:
  1473. {
  1474. return FALSE;
  1475. }
  1476. break;
  1477. default:
  1478. return FALSE;
  1479. break;
  1480. }
  1481. return TRUE;
  1482. }
  1483. //+---------------------------------------------------------------------------
  1484. //
  1485. // Method: CHTXIfExpressionValue::GetVectorValueDouble, public
  1486. //
  1487. // Synopsis: Returns the double value of a vector's element
  1488. //
  1489. // History: 96/Jun/27 DwightKr created
  1490. //
  1491. //----------------------------------------------------------------------------
  1492. BOOL CHTXIfExpressionValue::GetVectorValueDouble(unsigned index,
  1493. double & dblValue)
  1494. {
  1495. switch ( GetType() )
  1496. {
  1497. case VT_UI1 | VT_VECTOR:
  1498. VarR8FromUI1( _propVariant.caub.pElems[index], &dblValue );
  1499. break;
  1500. case VT_I1 | VT_VECTOR:
  1501. VarR8FromI1( _propVariant.caub.pElems[index], &dblValue );
  1502. break;
  1503. case VT_UI2 | VT_VECTOR:
  1504. VarR8FromUI2( _propVariant.caui.pElems[index], &dblValue );
  1505. break;
  1506. case VT_I2 | VT_VECTOR:
  1507. VarR8FromI2( _propVariant.cai.pElems[index], &dblValue );
  1508. break;
  1509. case VT_UI4 | VT_VECTOR:
  1510. VarR8FromUI4( _propVariant.caul.pElems[index], &dblValue );
  1511. break;
  1512. case VT_I4 | VT_VECTOR:
  1513. VarR8FromI4( _propVariant.cal.pElems[index], &dblValue );
  1514. break;
  1515. case VT_UI8 | VT_VECTOR:
  1516. dblValue = (double) _propVariant.cah.pElems[index].QuadPart;
  1517. break;
  1518. case VT_I8 | VT_VECTOR:
  1519. //
  1520. // hVal used instead of uhVal because latter coercion
  1521. // is not yet supported by x86 compiler.
  1522. //
  1523. dblValue = (double) _propVariant.cah.pElems[index].QuadPart;
  1524. break;
  1525. case VT_R4 | VT_VECTOR:
  1526. VarR8FromR4( _propVariant.caflt.pElems[index], &dblValue );
  1527. break;
  1528. case VT_R8 | VT_VECTOR:
  1529. dblValue = (double) _propVariant.cadbl.pElems[index];
  1530. break;
  1531. case VT_DATE | VT_VECTOR:
  1532. VarR8FromDate( _propVariant.cadate.pElems[index], &dblValue );
  1533. break;
  1534. case VT_BOOL | VT_VECTOR:
  1535. VarR8FromBool( _propVariant.cabool.pElems[index], &dblValue );
  1536. break;
  1537. case VT_CY | VT_VECTOR:
  1538. VarR8FromCy( _propVariant.cacy.pElems[index], &dblValue );
  1539. break;
  1540. default:
  1541. return FALSE;
  1542. break;
  1543. }
  1544. return TRUE;
  1545. }
  1546. //+---------------------------------------------------------------------------
  1547. //
  1548. // Method: CHTXIfExpressionValue::GetVectorValueWStr, public
  1549. //
  1550. // Synopsis: Returns the wide string representation of a vector's element
  1551. // in OLE memory.
  1552. //
  1553. // History: 96/Jun/27 DwightKr created
  1554. //
  1555. //----------------------------------------------------------------------------
  1556. BOOL CHTXIfExpressionValue::GetVectorValueWStr(unsigned index,
  1557. XCoMem<WCHAR> & wcsStringValue )
  1558. {
  1559. switch ( GetType() )
  1560. {
  1561. case VT_BSTR | VT_VECTOR:
  1562. case VT_LPWSTR | VT_VECTOR:
  1563. {
  1564. unsigned cwcStringValue;
  1565. if ( GetType() == (VT_LPWSTR | VT_VECTOR) )
  1566. {
  1567. cwcStringValue = wcslen( _propVariant.calpwstr.pElems[index] ) + 1;
  1568. }
  1569. else
  1570. {
  1571. cwcStringValue = BSTRLEN( _propVariant.cabstr.pElems[index] ) + 1;
  1572. }
  1573. wcsStringValue.Init( cwcStringValue );
  1574. RtlCopyMemory( wcsStringValue.GetPointer(),
  1575. _propVariant.calpwstr.pElems[index],
  1576. cwcStringValue * sizeof(WCHAR) );
  1577. }
  1578. break;
  1579. case VT_LPSTR | VT_VECTOR:
  1580. {
  1581. XArray<WCHAR> wcsBuffer;
  1582. ULONG cbBuffer = strlen(_propVariant.calpstr.pElems[index]) + 1;
  1583. ULONG cwcBuffer = MultiByteToXArrayWideChar( (UCHAR const *) _propVariant.calpstr.pElems[index],
  1584. cbBuffer,
  1585. _outputFormat.CodePage(),
  1586. wcsBuffer );
  1587. if ( 0 == cwcBuffer )
  1588. {
  1589. return FALSE;
  1590. }
  1591. wcsStringValue.Init( cwcBuffer + 1 );
  1592. RtlCopyMemory( wcsStringValue.GetPointer(),
  1593. wcsBuffer.GetPointer(),
  1594. (cwcBuffer+1) * sizeof(WCHAR) );
  1595. }
  1596. break;
  1597. default:
  1598. return FALSE;
  1599. break;
  1600. }
  1601. return TRUE;
  1602. }
  1603. //+---------------------------------------------------------------------------
  1604. //
  1605. // Method: CHTXIfExpressionValue::GetVectorValueStr, public
  1606. //
  1607. // Synopsis: Returns the string representation of a vector's element
  1608. // in OLE memory.
  1609. //
  1610. // History: 96/Jun/27 DwightKr created
  1611. //
  1612. //----------------------------------------------------------------------------
  1613. BOOL CHTXIfExpressionValue::GetVectorValueStr(unsigned index,
  1614. XCoMem<CHAR> & pszStringValue )
  1615. {
  1616. XCoMem<WCHAR> wcsStringValue;
  1617. if ( !GetVectorValueWStr( index, wcsStringValue ) )
  1618. {
  1619. return FALSE;
  1620. }
  1621. ULONG cwcBuffer = wcslen( wcsStringValue.GetPointer() ) + 1;
  1622. XArray<BYTE> pszMessage(cwcBuffer);
  1623. ULONG cbBuffer = WideCharToXArrayMultiByte( wcsStringValue.GetPointer(),
  1624. cwcBuffer,
  1625. _outputFormat.CodePage(),
  1626. pszMessage );
  1627. if ( 0 == cbBuffer )
  1628. {
  1629. return FALSE;
  1630. }
  1631. pszStringValue.Init( cbBuffer + 1 );
  1632. RtlCopyMemory( pszStringValue.GetPointer(),
  1633. pszMessage.GetPointer(),
  1634. cbBuffer + 1 );
  1635. return TRUE;
  1636. }
  1637. //+---------------------------------------------------------------------------
  1638. //
  1639. // Method: CHTXIfExpressionValue::GetVectorValueBStr, public
  1640. //
  1641. // Synopsis: Returns the B string representation of a vector's element
  1642. // in OLE memory.
  1643. //
  1644. // History: 96/Jun/27 DwightKr created
  1645. //
  1646. //----------------------------------------------------------------------------
  1647. BOOL CHTXIfExpressionValue::GetVectorValueBStr(unsigned index,
  1648. BSTR & bwszStringValue )
  1649. {
  1650. XCoMem<WCHAR> wszStringValue;
  1651. if ( !GetVectorValueWStr(index, wszStringValue) )
  1652. {
  1653. return FALSE;
  1654. }
  1655. bwszStringValue = SysAllocString( wszStringValue.GetPointer() );
  1656. if ( 0 == bwszStringValue )
  1657. {
  1658. THROW ( CException( E_OUTOFMEMORY ) );
  1659. }
  1660. return TRUE;
  1661. }