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.

761 lines
21 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Copyright (C) Microsoft Corporation, 1997 - 2000.
  4. //
  5. // File: ixsinfo.cxx
  6. //
  7. // Contents: Query SSO query information methods
  8. //
  9. // History: 30 Jan 1997 Alanw Created
  10. //
  11. //----------------------------------------------------------------------------
  12. #include "pch.cxx"
  13. #pragma hdrstop
  14. #include "ssodebug.hxx"
  15. #include "ixsso.hxx"
  16. #include "ixsinfo.hxx"
  17. #include <cgiesc.hxx>
  18. #include <string.hxx>
  19. #include <tgrow.hxx>
  20. //-----------------------------------------------------------------------------
  21. // CixssoQuery Methods
  22. //-----------------------------------------------------------------------------
  23. //+---------------------------------------------------------------------------
  24. //
  25. // Function: AddURLTerm - public inline
  26. //
  27. // Synopsis: Add a term to a URL QueryString
  28. //
  29. // Arguments: [vString] - virtual string in which the result is accumulated
  30. // [pwszTerm] - tag name, assumed to not need encoding
  31. // [pwszValue] - value part
  32. // [ulCodepage] - code page for URL encoding
  33. //
  34. // History: 19 Mar 1997 Alanw Created
  35. //
  36. //----------------------------------------------------------------------------
  37. inline void AddURLTerm(
  38. CVirtualString & vString,
  39. WCHAR * pwszTerm,
  40. WCHAR * pwszValue,
  41. ULONG ulCodepage)
  42. {
  43. if (vString.StrLen() > 0)
  44. vString.CharCat( L'&' );
  45. vString.StrCat(pwszTerm);
  46. URLEscapeW( pwszValue, vString, ulCodepage, TRUE );
  47. }
  48. //+---------------------------------------------------------------------------
  49. //
  50. // Member: CixssoQuery::QueryToURL - public
  51. //
  52. // Synopsis: Produce a URL QueryString from the state of the query object
  53. //
  54. // Arguments: [pbstrQueryString] - The URL-encoded query string is
  55. // returned here
  56. //
  57. // History: 19 Mar 1997 Alanw Created
  58. //
  59. //----------------------------------------------------------------------------
  60. STDMETHODIMP
  61. CixssoQuery::QueryToURL(BSTR * pbstrQueryString)
  62. {
  63. _err.Reset();
  64. SCODE sc = S_OK;
  65. CVirtualString vString( 512 );
  66. *pbstrQueryString = 0;
  67. TRY {
  68. if (_pwszCatalog)
  69. {
  70. AddURLTerm( vString, L"ct=", _pwszCatalog, _ulCodepage );
  71. }
  72. if (_pwszDialect)
  73. {
  74. AddURLTerm( vString, L"di=", _pwszDialect, _ulCodepage );
  75. }
  76. if (_pwszSort)
  77. {
  78. AddURLTerm( vString, L"so=", _pwszSort, _ulCodepage );
  79. }
  80. if (_pwszGroup)
  81. {
  82. AddURLTerm( vString, L"gr=", _pwszGroup, _ulCodepage );
  83. }
  84. if (_pwszRestriction)
  85. {
  86. AddURLTerm( vString, L"qu=", _pwszRestriction, _ulCodepage );
  87. }
  88. if (_maxResults)
  89. {
  90. WCHAR awchBuf[20];
  91. wsprintf(awchBuf, L"%d", _maxResults);
  92. AddURLTerm( vString, L"mh=", awchBuf, _ulCodepage );
  93. }
  94. if (_cFirstRows)
  95. {
  96. WCHAR awchBuf[20];
  97. wsprintf(awchBuf, L"%d", _cFirstRows);
  98. AddURLTerm( vString, L"fr=", awchBuf, _ulCodepage );
  99. }
  100. if (_StartHit.Get())
  101. {
  102. XGrowable<WCHAR> awchBuf;
  103. FormatLongVector( _StartHit.Get(), awchBuf );
  104. AddURLTerm( vString, L"sh=", awchBuf.Get(), _ulCodepage );
  105. }
  106. if (_fAllowEnumeration)
  107. {
  108. AddURLTerm( vString, L"ae=", L"1", _ulCodepage );
  109. }
  110. // OptimizeFor defaults to Hitcount
  111. if (_dwOptimizeFlags != eOptHitCount)
  112. {
  113. WCHAR awchBuf[4];
  114. unsigned i = 0;
  115. if (_dwOptimizeFlags & eOptPerformance)
  116. awchBuf[i++] = L'x';
  117. if (_dwOptimizeFlags & eOptRecall)
  118. awchBuf[i++] = L'r';
  119. if ( !(_dwOptimizeFlags & eOptHitCount) )
  120. awchBuf[i++] = L'h';
  121. awchBuf[i] = L'\0';
  122. AddURLTerm( vString, L"op=", awchBuf, _ulCodepage );
  123. }
  124. //
  125. // The URL encoded string is assembled. Copy it into a BSTR for return.
  126. //
  127. BSTR bstr = SysAllocStringLen( vString.GetPointer(), vString.StrLen() );
  128. if (0 == bstr)
  129. THROW(CException( E_OUTOFMEMORY ) );
  130. *pbstrQueryString = bstr;
  131. }
  132. CATCH (CException, e)
  133. {
  134. sc = GetOleError( e );
  135. }
  136. END_CATCH
  137. if (FAILED(sc))
  138. {
  139. SetError( sc, OLESTR("QueryToURL") );
  140. }
  141. return sc;
  142. }
  143. //+---------------------------------------------------------------------------
  144. //
  145. // Member: CixssoQuery::SetQueryFromURL - public
  146. //
  147. // Synopsis: Parse a URL QueryString and update object state accordingly.
  148. //
  149. // Arguments: [bstrQueryString] - The input URL-encoded query string
  150. //
  151. // History: 20 Mar 1997 Alanw Created
  152. //
  153. //----------------------------------------------------------------------------
  154. STDMETHODIMP
  155. CixssoQuery::SetQueryFromURL(BSTR bstrQueryString)
  156. {
  157. _err.Reset();
  158. SCODE sc = S_OK;
  159. TRY {
  160. CQueryInfo Info;
  161. ixssoDebugOut(( DEB_ITRACE, "QUERY_STRING = %ws\n", bstrQueryString ));
  162. //
  163. // Parse the string, which has the following format:
  164. //
  165. //
  166. // tag1=Value1&tag2=value2&tag3=value+%7c+0&foo&bar
  167. //
  168. unsigned cchBuffer = SysStringLen(bstrQueryString);
  169. WCHAR * pwszToken = (WCHAR *)bstrQueryString;
  170. while ( pwszToken && (L'\0' != *pwszToken) )
  171. {
  172. //
  173. // Find the value on the right hand side of the equal sign.
  174. //
  175. WCHAR *pwszTag = pwszToken;
  176. WCHAR *pwszValue = wcschr( pwszTag, L'=' );
  177. if ( 0 != pwszValue )
  178. {
  179. unsigned cchTag = CiPtrToUint( pwszValue - pwszTag );
  180. pwszValue++;
  181. //
  182. // Point to the next Tag.
  183. //
  184. pwszToken = wcschr( pwszToken, L'&' );
  185. ULONG cchValue;
  186. if ( 0 != pwszToken )
  187. {
  188. if ( pwszToken < pwszValue )
  189. {
  190. //
  191. // We have a construction like foo&bar=value. Set
  192. // the tag with a null value and go on to the next
  193. // tag=value pair.
  194. //
  195. cchValue = 0;
  196. }
  197. else
  198. cchValue = CiPtrToUlong( pwszToken - pwszValue );
  199. pwszToken++;
  200. }
  201. else
  202. {
  203. cchValue = CiPtrToUlong( (WCHAR *)&bstrQueryString[cchBuffer] - pwszValue );
  204. }
  205. if ( 0 == cchValue )
  206. {
  207. ixssoDebugOut(( DEB_ITRACE,
  208. "SetQueryFromURL - setting %.*ws=NULL\n",
  209. cchTag, pwszTag ));
  210. XPtrST<WCHAR> xpValue( 0 );
  211. Info.SetQueryParameter( pwszTag, xpValue );
  212. }
  213. else
  214. {
  215. XGrowable<BYTE> achBuf( cchValue );
  216. for ( unsigned i=0; i<cchValue; i++ )
  217. {
  218. Win4Assert( pwszValue[i] < 0x100 );
  219. achBuf[i] = (BYTE) pwszValue[i];
  220. }
  221. XPtrST<WCHAR> xpwchValue( new WCHAR[cchValue+1] );
  222. DecodeURLEscapes( achBuf.Get(),
  223. cchValue,
  224. xpwchValue.GetPointer(),
  225. _ulCodepage );
  226. ixssoDebugOut(( DEB_ITRACE,
  227. "SetQueryFromURL - setting %.*ws=%ws\n",
  228. cchTag, pwszTag,
  229. xpwchValue.GetPointer() ));
  230. Info.SetQueryParameter( pwszTag, xpwchValue );
  231. }
  232. }
  233. else if ( 0 != pwszToken )
  234. {
  235. //
  236. // There was no tag=value pair found; a lonely '&' was
  237. // found. Skip it and proceed to the next '&'.
  238. //
  239. pwszToken = wcschr( pwszToken+1, L'&' );
  240. }
  241. }
  242. Info.MakeFinalQueryString();
  243. if (Info.GetQuery())
  244. {
  245. delete _pwszRestriction;
  246. _pwszRestriction = Info.AcquireQuery();
  247. }
  248. if (Info.GetCatalog())
  249. {
  250. delete _pwszCatalog;
  251. _pwszCatalog = Info.AcquireCatalog();
  252. }
  253. if ( Info.GetDialect() )
  254. {
  255. delete _pwszDialect;
  256. _pwszDialect = Info.AcquireDialect();
  257. }
  258. if (Info.GetSort())
  259. {
  260. delete _pwszSort;
  261. _pwszSort = Info.AcquireSort();
  262. }
  263. if (Info.GetGroup())
  264. {
  265. delete _pwszGroup;
  266. _pwszGroup = Info.AcquireGroup();
  267. }
  268. if (Info.GetMaxHits())
  269. {
  270. _maxResults = Info.GetMaxHits();
  271. }
  272. if (Info.GetFirstRows())
  273. {
  274. _cFirstRows = Info.GetFirstRows();
  275. }
  276. if (Info.GetStartHit().Count())
  277. {
  278. unsigned cHits = Info.GetStartHit().Count();
  279. SCODE sc;
  280. SAFEARRAY* psa;
  281. XSafeArray xsa;
  282. psa = SafeArrayCreateVector(VT_I4, 1, cHits);
  283. if( ! psa )
  284. THROW(CException( E_OUTOFMEMORY ));
  285. xsa.Set(psa);
  286. for (unsigned i=1; i<=cHits; i++)
  287. {
  288. long rgIx[1];
  289. LONG lVal = Info.GetStartHit().Get(i-1);
  290. rgIx[0] = (long)i;
  291. sc = SafeArrayPutElement( xsa.Get(), rgIx, &lVal );
  292. if ( FAILED( sc ) )
  293. THROW( CException( sc ) );
  294. }
  295. _StartHit.Destroy();
  296. _StartHit.Set( xsa.Acquire() );
  297. }
  298. if (Info.WasAllowEnumSet())
  299. {
  300. _fAllowEnumeration = Info.GetAllowEnum();
  301. }
  302. if (eOptHitCount != Info.GetOptimizeFor())
  303. {
  304. _dwOptimizeFlags = Info.GetOptimizeFor();
  305. }
  306. }
  307. CATCH( CIxssoException, e )
  308. {
  309. sc = e.GetErrorCode();
  310. Win4Assert( !SUCCEEDED(sc) );
  311. SetError( sc, OLESTR("SetqueryFromURL"), eIxssoError );
  312. }
  313. AND_CATCH( CException, e )
  314. {
  315. sc = GetOleError( e );
  316. SetError( sc, OLESTR("SetQueryFromURL") );
  317. }
  318. END_CATCH
  319. return sc;
  320. }
  321. //-----------------------------------------------------------------------------
  322. // CQueryInfo Methods
  323. //-----------------------------------------------------------------------------
  324. //+---------------------------------------------------------------------------
  325. //
  326. // Function: EncodeTagString - inline
  327. //
  328. // Synopsis: Encode a one or two character tag into a DWORD value
  329. //
  330. // Arguments: [pwszTag] - a pointer to the tag
  331. // [dwCodedTag] - the coded value which is returned
  332. // [iParam] - the numeric value for the tag
  333. //
  334. // Notes: Tags consisting of one alpha character, two alpha characters
  335. // or one alpha followed by a numeric character are recognized
  336. // and converted into a DWORD (whose value just happens to be
  337. // the same as a one or two character character constant for the
  338. // alpha characters in the tag). If the third form is recognized,
  339. // the iParam parameter gets the value of the numeric character,
  340. // otherwise iParam is zero.
  341. //
  342. // dwCodedTag will be zero if pwszTag is not one of the allowed
  343. // forms.
  344. //
  345. // History: 19 Mar 1997 Alanw Created
  346. //
  347. //----------------------------------------------------------------------------
  348. inline void EncodeTagString( WCHAR const * pwszTag,
  349. DWORD & dwCodedTag,
  350. USHORT & iParam )
  351. {
  352. dwCodedTag = 0;
  353. iParam = 0;
  354. if (0 == pwszTag || L'\0' == *pwszTag)
  355. return;
  356. if (isalpha(*pwszTag))
  357. {
  358. dwCodedTag = towupper(*pwszTag) & 0xFF;
  359. if (isalpha(pwszTag[1]))
  360. {
  361. dwCodedTag <<= 8;
  362. dwCodedTag |= (towupper(pwszTag[1]) & 0xFF);
  363. }
  364. else if (isdigit(pwszTag[1]))
  365. iParam = pwszTag[1] - L'0';
  366. else if (L'=' == pwszTag[1] ||
  367. L'&' == pwszTag[1] ||
  368. L'\0' == pwszTag[1])
  369. return;
  370. else
  371. {
  372. dwCodedTag = 0;
  373. return;
  374. }
  375. if ( L'=' != pwszTag[2] &&
  376. L'&' != pwszTag[2] &&
  377. L'\0' != pwszTag[2])
  378. dwCodedTag = 0;
  379. }
  380. return;
  381. }
  382. //+---------------------------------------------------------------------------
  383. //
  384. // Member: CQueryInfo::SetQueryParameter - public
  385. //
  386. // Synopsis: Process a QueryString parameter
  387. //
  388. // Arguments: [pwszTag] - the tag name for the parameter
  389. // [pwszValue] - the value for the parameter
  390. //
  391. // History: 19 Mar 1997 Alanw Created
  392. //
  393. //----------------------------------------------------------------------------
  394. void CQueryInfo::SetQueryParameter( WCHAR const * pwszTag,
  395. XPtrST<WCHAR> & pwszValue )
  396. {
  397. DWORD dwParamCode;
  398. USHORT iParam;
  399. EncodeTagString( pwszTag, dwParamCode, iParam );
  400. if (0 == dwParamCode)
  401. return;
  402. for (unsigned i=0; i<cQueryTagTable; i++)
  403. if (dwParamCode == aQueryTagTable[i].dwTagName)
  404. break;
  405. if (i == cQueryTagTable)
  406. return;
  407. i = aQueryTagTable[i].qtQueryTagType;
  408. switch (i)
  409. {
  410. case qtQueryFullText:
  411. AddToParam( _xpQuery, pwszValue );
  412. break;
  413. case qtMaxHits:
  414. {
  415. LONG cNum = 0;
  416. if (0 != pwszValue.GetPointer())
  417. cNum = _wtoi( pwszValue.GetPointer() );
  418. if (cNum > 0)
  419. {
  420. _maxHits = cNum;
  421. }
  422. else
  423. {
  424. ixssoDebugOut(( DEB_TRACE,
  425. "CIxsQueryInfo::SetQueryParameter - invalid numeric %ws\n",
  426. pwszValue.GetPointer() ));
  427. }
  428. }
  429. break;
  430. case qtFirstRows:
  431. {
  432. LONG cNum = 0;
  433. if (0 != pwszValue.GetPointer())
  434. cNum = _wtoi( pwszValue.GetPointer() );
  435. if (cNum > 0)
  436. {
  437. _cFirstRows = cNum;
  438. }
  439. else
  440. {
  441. ixssoDebugOut(( DEB_TRACE,
  442. "CIxsQueryInfo::SetQueryParameter - invalid numeric %ws\n",
  443. pwszValue.GetPointer() ));
  444. }
  445. }
  446. break;
  447. case qtStartHit:
  448. ParseNumberVectorString( pwszValue.GetPointer(), GetStartHit() );
  449. break;
  450. case qtCatalog:
  451. AddToParam( _xpCatalog, pwszValue );
  452. break;
  453. case qtDialect:
  454. AddToParam( _xpDialect, pwszValue );
  455. break;
  456. case qtSort:
  457. AddToParam( _xpSort, pwszValue );
  458. break;
  459. case qtSortDown:
  460. if (pwszValue.GetPointer())
  461. AddToParam( _xpSort, pwszValue, L",", L"[d]" );
  462. break;
  463. #if IXSSO_CATEGORIZE == 1
  464. case qtGroup:
  465. AddToParam( _xpGroup, pwszValue );
  466. break;
  467. case qtGroupDown:
  468. if (pwszValue.GetPointer())
  469. AddToParam( _xpGroup, pwszValue, L",", L"[d]" );
  470. break;
  471. #endif // IXSSO_CATEGORIZE == 1
  472. case qtAllowEnumeration:
  473. _fAllowEnumeration = 0 != pwszValue.GetPointer() &&
  474. iswdigit(*pwszValue.GetPointer()) &&
  475. *pwszValue.GetPointer() != L'0';
  476. _fSetAllowEnumeration = 1;
  477. break;
  478. case qtOptimizeFor:
  479. {
  480. WCHAR * pwszVal = pwszValue.GetPointer();
  481. while (pwszVal && *pwszVal)
  482. {
  483. WCHAR chKey = towupper(*pwszVal);
  484. if (chKey == L'X')
  485. {
  486. _dwOptimizeFor &= ~eOptRecall;
  487. _dwOptimizeFor |= eOptPerformance;
  488. }
  489. else if (chKey == L'R')
  490. {
  491. _dwOptimizeFor &= ~eOptPerformance;
  492. _dwOptimizeFor |= eOptRecall;
  493. }
  494. else if (chKey == L'H')
  495. {
  496. _dwOptimizeFor &= ~eOptHitCount;
  497. }
  498. // else if (chKey == L'P')
  499. // _dwOptimizeFor |= eOptPrecision;
  500. pwszVal++;
  501. }
  502. break;
  503. }
  504. case qtColumn:
  505. Win4Assert( iParam >= 0 && iParam < 10 );
  506. SetBuiltupQueryTerm( _aQueryCol, iParam, pwszValue );
  507. break;
  508. case qtOperator:
  509. Win4Assert( iParam >= 0 && iParam < 10 );
  510. SetBuiltupQueryTerm( _aQueryOp, iParam, pwszValue );
  511. break;
  512. case qtQuery:
  513. Win4Assert( iParam >= 0 && iParam < 10 );
  514. SetBuiltupQueryTerm( _aQueryVal, iParam, pwszValue );
  515. break;
  516. default:
  517. ixssoDebugOut(( DEB_WARN, "SetQueryFromURL - reserved tag %.2ws\n", pwszTag ));
  518. THROW( CIxssoException(MSG_IXSSO_INVALID_QUERYSTRING_TAG, 0) );
  519. break;
  520. }
  521. return;
  522. }
  523. //+---------------------------------------------------------------------------
  524. //
  525. // Member: CQueryInfo::AddToParam - private
  526. //
  527. // Synopsis: Append a string to a parameter
  528. //
  529. // Arguments: [xpString] - A smart pointer to the string to be appended to
  530. // [pwszValue] - The value to be added to xpString
  531. // [pwszPre] - the separator for multiple values in xpString.
  532. // Defaults to ','.
  533. // [pwszPost] - unconditionally appended to pwszValue
  534. //
  535. // History: 19 Mar 1997 Alanw Created
  536. //
  537. //----------------------------------------------------------------------------
  538. void CQueryInfo::AddToParam( XPtrST<WCHAR> & xpString,
  539. XPtrST<WCHAR> & pwszValue,
  540. WCHAR const * pwszPre,
  541. WCHAR const * pwszPost )
  542. {
  543. unsigned cch = 0;
  544. if (0 == xpString.GetPointer())
  545. {
  546. if (0 == pwszPost)
  547. {
  548. xpString.Set( pwszValue.Acquire() );
  549. }
  550. else
  551. {
  552. if (pwszValue.GetPointer())
  553. cch = wcslen(pwszValue.GetPointer());
  554. xpString.Set( new WCHAR[cch + wcslen(pwszPost) + 1] );
  555. if (cch)
  556. wcsncpy(xpString.GetPointer(), pwszValue.GetPointer(), cch);
  557. wcscpy(xpString.GetPointer() + cch, pwszPost);
  558. }
  559. return;
  560. }
  561. cch = wcslen(xpString.GetPointer());
  562. cch += pwszPre ? wcslen(pwszPre) : wcslen(L",");
  563. if (pwszValue.GetPointer())
  564. cch += wcslen( pwszValue.GetPointer() );
  565. if (pwszPost)
  566. cch += wcslen( pwszPost );
  567. XPtrST<WCHAR> xpDest( new WCHAR[cch+1] );
  568. wcscpy(xpDest.GetPointer(), xpString.GetPointer());
  569. wcscat(xpDest.GetPointer(), pwszPre ? pwszPre : L",");
  570. if (pwszValue.GetPointer())
  571. wcscat(xpDest.GetPointer(), pwszValue.GetPointer());
  572. if (pwszPost)
  573. wcscat(xpDest.GetPointer(), pwszPost);
  574. xpString.Free();
  575. xpString.Set( xpDest.Acquire() );
  576. }
  577. //+---------------------------------------------------------------------------
  578. //
  579. // Member: CQueryInfo::SetBuiltupQueryTerm - private
  580. //
  581. // Synopsis: Add an individual partial query term to an array of terms.
  582. //
  583. // Arguments: [apString] - A dynamic array of string pointers
  584. // [iTerm] - The index of the term to be added
  585. // [pwszValue] - The value to be added to apString
  586. //
  587. // Notes: If the array entry for the term is already set, it is
  588. // overwritten.
  589. //
  590. // History: 21 Mar 1997 Alanw Created
  591. //
  592. //----------------------------------------------------------------------------
  593. void CQueryInfo::SetBuiltupQueryTerm( CDynArray<WCHAR> & apString,
  594. unsigned iTerm,
  595. XPtrST<WCHAR> & pwszValue )
  596. {
  597. Win4Assert( iTerm < 10 );
  598. delete apString.Acquire(iTerm);
  599. apString.Add( pwszValue.GetPointer(), iTerm );
  600. pwszValue.Acquire();
  601. }
  602. //+---------------------------------------------------------------------------
  603. //
  604. // Member: CQueryInfo::MakeFinalQueryString - public
  605. //
  606. // Synopsis: Combine the built-up query terms into the complete query
  607. // restriction.
  608. //
  609. // Arguments: - NONE -
  610. //
  611. // History: 20 Mar 1997 Alanw Created
  612. //
  613. //----------------------------------------------------------------------------
  614. void CQueryInfo::MakeFinalQueryString( )
  615. {
  616. //
  617. // Add query terms to any pre-existing full query string
  618. //
  619. for (unsigned i = 0; i < 10; i++)
  620. {
  621. // Ignore the term if the qn= part was not set.
  622. if ( _aQueryVal[i] != 0 )
  623. {
  624. XPtrST<WCHAR> xpStr(0);
  625. AddToParam( _xpQuery, xpStr, IMPLIED_QUERY_TERM_OPERATOR, L" ( ");
  626. if ( _aQueryCol[i] != 0 )
  627. {
  628. xpStr.Set( _aQueryCol.Acquire(i) );
  629. AddToParam( _xpQuery, xpStr, L"", L" ");
  630. xpStr.Free();
  631. }
  632. if ( _aQueryOp[i] != 0 )
  633. {
  634. xpStr.Set( _aQueryOp.Acquire(i) );
  635. AddToParam( _xpQuery, xpStr, L"", L" ");
  636. xpStr.Free();
  637. }
  638. if ( _aQueryVal[i] != 0 )
  639. {
  640. xpStr.Set( _aQueryVal.Acquire(i) );
  641. AddToParam( _xpQuery, xpStr, L"", L" ");
  642. xpStr.Free();
  643. }
  644. AddToParam( _xpQuery, xpStr, L")");
  645. }
  646. }
  647. }