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.

841 lines
27 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: QPARSE.CXX
  7. //
  8. // Contents: Query parser
  9. //
  10. // Classes: CQParse -- query parser
  11. //
  12. // History: 19-Sep-91 BartoszM Implemented.
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <qparse.hxx>
  18. #include <norm.hxx>
  19. #include <drep.hxx>
  20. #include <cci.hxx>
  21. #include <pidmap.hxx>
  22. #include <fa.hxx>
  23. #include <compare.hxx>
  24. #include <cichkstk.hxx>
  25. #include "qkrep.hxx"
  26. DECLARE_SMARTP( InternalPropertyRestriction )
  27. static GUID guidQuery = DBQUERYGUID;
  28. static CFullPropSpec psUnfiltered( guidQuery, DISPID_QUERY_UNFILTERED );
  29. static GUID guidStorage = PSGUID_STORAGE;
  30. static CFullPropSpec psFilename( guidStorage, PID_STG_NAME );
  31. static CFullPropSpec psRevName( guidQuery, DISPID_QUERY_REVNAME );
  32. //+---------------------------------------------------------------------------
  33. //
  34. // Member: CQParse::CQParse, public
  35. //
  36. // Synopsis: Break phrases, normalize, and stem the query expression
  37. //
  38. // Arguments: [pidmap] -- Propid mapper
  39. // [langList] -- Language list
  40. //
  41. // History: 19-Sep-91 BartoszM Created.
  42. //
  43. //----------------------------------------------------------------------------
  44. CQParse::CQParse( CPidMapper & pidmap, CLangList & langList )
  45. : _flags(0),
  46. _pidmap( pidmap ),
  47. _langList( langList ),
  48. _lcidSystemDefault( GetSystemDefaultLCID() )
  49. {
  50. }
  51. //+---------------------------------------------------------------------------
  52. //
  53. // Member: CQParse::Parse, public
  54. //
  55. // Synopsis: Recursively parse expression
  56. //
  57. // Arguments: [pRst] -- Tree of query expressions
  58. //
  59. // Returns: Possibly modified expression
  60. //
  61. // History: 19-Sep-91 BartoszM Created.
  62. // 18-Jan-92 KyleP Use restrictions
  63. // 15-May-96 DwightKr Add check for NULL NOT restriction
  64. //
  65. // Notes: The return CRestriction will be different than [pRst].
  66. // [pRst] is not touched.
  67. //
  68. //----------------------------------------------------------------------------
  69. CRestriction* CQParse::Parse( CRestriction* pRst )
  70. {
  71. ciThrowIfLowOnStack();
  72. // go through leaves:
  73. // normalize values
  74. // break and normalize phrases (create phrase nodes)
  75. // GenerateMethod level 1 -- convert to ranges
  76. // higher GenerateMethod levels -- use stemmer
  77. if ( pRst->IsLeaf() )
  78. {
  79. return Leaf ( pRst );
  80. }
  81. else
  82. {
  83. if ( pRst->Type() == RTNot )
  84. {
  85. CNotRestriction * pnrst = (CNotRestriction *)pRst;
  86. XRestriction xRst( Parse( pnrst->GetChild() ) );
  87. if ( xRst.GetPointer() == 0 )
  88. {
  89. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  90. }
  91. CNotRestriction *pNotRst = new CNotRestriction( xRst.GetPointer() );
  92. Win4Assert( pNotRst->IsValid() );
  93. xRst.Acquire();
  94. return pNotRst;
  95. }
  96. CNodeRestriction* pnrstSource = pRst->CastToNode();
  97. XNodeRestriction xnrstTarget;
  98. BOOL fVector;
  99. if ( pRst->Type() == RTVector )
  100. {
  101. fVector = TRUE;
  102. xnrstTarget.Set( new CVectorRestriction( ((CVectorRestriction *)pRst)->RankMethod(),
  103. pRst->CastToNode()->Count() ) );
  104. }
  105. else
  106. {
  107. fVector = FALSE;
  108. xnrstTarget.Set( new CNodeRestriction( pRst->Type(),
  109. pRst->CastToNode()->Count() ) );
  110. }
  111. Win4Assert( xnrstTarget->IsValid() );
  112. //
  113. // Vector nodes must be treated slightly differently than
  114. // AND/OR/ANDNOT nodes. Noise words must be placeholders
  115. // in a vector node.
  116. //
  117. BOOL fAndNode = ( xnrstTarget->Type() == RTAnd || xnrstTarget->Type() == RTProximity );
  118. ULONG cOrCount = ( fAndNode ? 1: pnrstSource->Count() ); // Number of non-noise OR components
  119. for ( unsigned i = 0; i < pnrstSource->Count(); i++ )
  120. {
  121. CRestriction * px = Parse ( pnrstSource->GetChild(i) );
  122. //
  123. // Don't store noise phrases (null nodes) during parse,
  124. // *unless* this is a vector node.
  125. if ( 0 == px && fVector )
  126. {
  127. px = new CRestriction;
  128. }
  129. if ( 0 != px )
  130. {
  131. XRestriction xRst( px );
  132. xnrstTarget->AddChild ( px );
  133. xRst.Acquire();
  134. }
  135. else
  136. {
  137. cOrCount--;
  138. if ( 0 == cOrCount ) // all components are noise only
  139. THROW( CException( QUERY_E_ALLNOISE ) );
  140. }
  141. }
  142. return xnrstTarget.Acquire();
  143. }
  144. } //Parse
  145. //+---------------------------------------------------------------------------
  146. //
  147. // Member: CQParse::Leaf, private
  148. //
  149. // Synopsis: Parse the leaf node of expression tree
  150. //
  151. // Arguments: [pExpr] -- leaf expression
  152. //
  153. // Returns: Possibly modified expression
  154. //
  155. // Requires: pExpr->IsLeaf() TRUE
  156. //
  157. // History: 19-Sep-91 BartoszM Created.
  158. // 18-Jan-92 KyleP Use restrictions
  159. // 05-Nov-93 DwightKr Changed PutUnsignedValue => PutValue
  160. //
  161. //----------------------------------------------------------------------------
  162. CRestriction* CQParse::Leaf ( CRestriction* pRst )
  163. {
  164. Win4Assert ( pRst->IsLeaf() );
  165. switch( pRst->Type() )
  166. {
  167. case RTContent:
  168. {
  169. CContentRestriction* pContRst = (CContentRestriction *) pRst;
  170. ULONG GenerateMethod = pContRst->GenerateMethod();
  171. if ( GenerateMethod > GENERATE_METHOD_MAX_USER )
  172. {
  173. vqDebugOut(( DEB_ERROR,
  174. "QParse: GenerateMethod 0x%x > GENERATE_METHOD_MAX_USER\n",
  175. GenerateMethod ));
  176. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  177. }
  178. CQueryKeyRepository keyRep( GenerateMethod );
  179. CRestriction * pPhraseRst;
  180. switch ( BreakPhrase ( pContRst->GetPhrase(),
  181. pContRst->GetProperty(),
  182. pContRst->GetLocale(),
  183. GenerateMethod,
  184. keyRep,
  185. 0,
  186. _pidmap,
  187. _langList) )
  188. {
  189. case BP_NOISE:
  190. _flags |= CI_NOISE_IN_PHRASE;
  191. // Note fall through...
  192. case BP_OK:
  193. pPhraseRst = keyRep.AcqRst();
  194. if ( pPhraseRst )
  195. pPhraseRst->SetWeight( pRst->Weight() );
  196. else
  197. _flags |= CI_NOISE_PHRASE;
  198. break;
  199. default:
  200. Win4Assert( !"How did we get here?" );
  201. case BP_INVALID_PROPERTY:
  202. pPhraseRst = 0;
  203. break;
  204. } // switch
  205. return pPhraseRst;
  206. break;
  207. }
  208. case RTNatLanguage:
  209. {
  210. CNatLanguageRestriction* pNatLangRst = (CNatLanguageRestriction *) pRst;
  211. CVectorKeyRepository vecKeyRep( pNatLangRst->GetProperty(),
  212. pNatLangRst->GetLocale(),
  213. pRst->Weight(),
  214. _pidmap,
  215. _langList );
  216. CRestriction* pVectorRst;
  217. switch ( BreakPhrase ( pNatLangRst->GetPhrase(),
  218. pNatLangRst->GetProperty(),
  219. pNatLangRst->GetLocale(),
  220. GENERATE_METHOD_INFLECT,
  221. vecKeyRep,
  222. &vecKeyRep,
  223. _pidmap,
  224. _langList ) )
  225. {
  226. case BP_NOISE:
  227. _flags |= CI_NOISE_IN_PHRASE;
  228. // Note fall through...
  229. case BP_OK:
  230. pVectorRst = vecKeyRep.AcqRst();
  231. if ( pVectorRst )
  232. pVectorRst->SetWeight( pRst->Weight() );
  233. else
  234. _flags |= CI_NOISE_PHRASE;
  235. break;
  236. default:
  237. Win4Assert( !"How did we get here?" );
  238. case BP_INVALID_PROPERTY:
  239. pVectorRst = 0;
  240. break;
  241. } // switch
  242. return pVectorRst;
  243. break;
  244. }
  245. case RTProperty:
  246. {
  247. CPropertyRestriction * prstProp = (CPropertyRestriction *)pRst;
  248. if ( getBaseRelop(prstProp->Relation()) > PRSomeBits )
  249. {
  250. vqDebugOut(( DEB_ERROR,
  251. "QParse: Invalid comparison operator %d\n",
  252. prstProp->Relation() ));
  253. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  254. }
  255. PROPID pid = _pidmap.NameToPid( prstProp->GetProperty() );
  256. if ( pidInvalid != pid )
  257. pid = _pidmap.PidToRealPid( pid );
  258. if ( pidInvalid == pid )
  259. {
  260. vqDebugOut(( DEB_ERROR,
  261. "QParse: Invalid property\n" ));
  262. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  263. }
  264. CInternalPropertyRestriction * prstIProp =
  265. new CInternalPropertyRestriction( prstProp->Relation(),
  266. pid,
  267. prstProp->Value() );
  268. Win4Assert( prstIProp->IsValid() );
  269. XInternalPropertyRestriction xrstIProp( prstIProp );
  270. //
  271. // If the property restriction is over a string value, then create
  272. // a helper content restriction.
  273. //
  274. switch( prstProp->Value().Type() )
  275. {
  276. case VT_LPSTR:
  277. AddLpstrHelper( prstProp, prstIProp );
  278. break;
  279. case VT_LPWSTR:
  280. AddLpwstrHelper( prstProp, prstIProp );
  281. break;
  282. case VT_LPWSTR | VT_VECTOR:
  283. AddLpwstrVectorHelper( prstProp, prstIProp );
  284. break;
  285. case VT_BOOL:
  286. if ( prstProp->Value().GetBOOL() != FALSE &&
  287. prstProp->Relation() == PREQ &&
  288. prstProp->GetProperty() == psUnfiltered )
  289. {
  290. delete xrstIProp.Acquire();
  291. CUnfilteredRestriction *pUnfiltRst = new CUnfilteredRestriction;
  292. return( pUnfiltRst );
  293. }
  294. break;
  295. default:
  296. break;
  297. }
  298. return( xrstIProp.Acquire() );
  299. }
  300. default:
  301. {
  302. vqDebugOut(( DEB_ERROR,
  303. "QParse: Invalid restriction type %d\n",
  304. pRst->Type() ));
  305. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  306. return 0;
  307. }
  308. }
  309. } //Leaf
  310. //+---------------------------------------------------------------------------
  311. //
  312. // Member: CQParse::AddLpwstrHelper, private
  313. //
  314. // Synopsis: Add content helpers for VT_LPWSTR properties.
  315. //
  316. // Arguments: [prstProp] -- Property restriction (input)
  317. // [prstIProp] -- Internal property restriction (output)
  318. //
  319. // History: 03-Oct-95 KyleP Broke out as method.
  320. //
  321. //----------------------------------------------------------------------------
  322. void CQParse::AddLpwstrHelper( CPropertyRestriction * prstProp,
  323. CInternalPropertyRestriction * prstIProp )
  324. {
  325. //
  326. // For equality, we create a content restriction with GenerateMethod level 0.
  327. //
  328. if ( prstProp->Relation() == PREQ )
  329. {
  330. CQueryKeyRepository keyRep( GENERATE_METHOD_EXACT );
  331. BreakPhrase ( (WCHAR *)prstProp->Value().GetLPWSTR(),
  332. prstProp->GetProperty(),
  333. _lcidSystemDefault,
  334. GENERATE_METHOD_EXACT,
  335. keyRep,
  336. 0,
  337. _pidmap,
  338. _langList );
  339. prstIProp->SetContentHelper( keyRep.AcqRst() );
  340. }
  341. //
  342. // For regular expression, create a GenerateMethod match for any fixed prefix
  343. // on the string.
  344. //
  345. else if ( prstProp->Relation() == PRRE )
  346. {
  347. const MAX_PREFIX_LENGTH = 50;
  348. unsigned i = wcscspn( prstProp->Value().GetLPWSTR(),
  349. awcSpecialRegex );
  350. //
  351. // Should the 0 below be a registry parameter?
  352. //
  353. if ( i > 0 )
  354. {
  355. WCHAR wcs[MAX_PREFIX_LENGTH];
  356. if ( i > sizeof(wcs)/sizeof(WCHAR) - 2 )
  357. i = sizeof(wcs)/sizeof(WCHAR) - 2;
  358. memcpy( wcs, prstProp->Value().GetLPWSTR(), i*sizeof(WCHAR) );
  359. wcs[i] = 0;
  360. //
  361. // Trickery: Key repository is GENERATE_METHOD_PREFIX which turns key into ranges.
  362. // Phrase is broken with GENERATE_METHOD_EXACTPREFIXMATCH which does 'exact'
  363. // prefix matching: e.g. it uses the noise word list. The result is
  364. // that we match ranges, but don't set a content helper if we hit
  365. // a noise word. This is different from a user GENERATE_METHOD_PREFIX
  366. // which uses a very minimal noise word list (only 1 character
  367. // prefixes are noise).
  368. //
  369. CQueryKeyRepository keyRep( GENERATE_METHOD_PREFIX );
  370. if ( BP_OK == BreakPhrase ( wcs,
  371. prstProp->GetProperty(),
  372. _lcidSystemDefault,
  373. GENERATE_METHOD_EXACTPREFIXMATCH,
  374. keyRep,
  375. 0,
  376. _pidmap,
  377. _langList ) )
  378. {
  379. prstIProp->SetContentHelper( keyRep.AcqRst() );
  380. }
  381. }
  382. //
  383. // If this is the filename property, then add to the content helper
  384. // the reversed suffix string w/o wildcards. For *.cxx we would
  385. // add xxc.
  386. //
  387. if ( prstProp->GetProperty() == psFilename )
  388. {
  389. WCHAR wcs[MAX_PREFIX_LENGTH];
  390. WCHAR const * pBegin = prstProp->Value().GetLPWSTR();
  391. WCHAR const * pEnd = pBegin + wcslen(pBegin) - 1;
  392. i = 0;
  393. for ( ; pEnd >= pBegin && i < MAX_PREFIX_LENGTH - 1 ; pEnd-- )
  394. {
  395. if ( wcschr( awcSpecialRegexReverse, *pEnd ) == 0 )
  396. wcs[i++] = *pEnd;
  397. else
  398. {
  399. wcs[i] = 0;
  400. break;
  401. }
  402. }
  403. if ( i < MAX_PREFIX_LENGTH )
  404. wcs[i] = 0;
  405. wcs[MAX_PREFIX_LENGTH - 1] = 0;
  406. if ( i > 0 )
  407. {
  408. CQueryKeyRepository keyRep( GENERATE_METHOD_PREFIX );
  409. if ( prstIProp->GetContentHelper() == 0 )
  410. {
  411. if ( BP_OK == BreakPhrase ( wcs,
  412. psRevName,
  413. _lcidSystemDefault,
  414. GENERATE_METHOD_EXACTPREFIXMATCH,
  415. keyRep,
  416. 0,
  417. _pidmap,
  418. _langList ) )
  419. {
  420. prstIProp->SetContentHelper( keyRep.AcqRst() );
  421. }
  422. }
  423. else
  424. {
  425. if ( BP_OK == BreakPhrase ( wcs,
  426. psRevName,
  427. _lcidSystemDefault,
  428. GENERATE_METHOD_EXACTPREFIXMATCH,
  429. keyRep,
  430. 0,
  431. _pidmap,
  432. _langList ) )
  433. {
  434. CNodeRestriction *pNodeRst = new CNodeRestriction( RTAnd, 2 );
  435. XNodeRestriction rstAnd( pNodeRst );
  436. Win4Assert( rstAnd->IsValid() );
  437. unsigned posOrig;
  438. rstAnd->AddChild( prstIProp->GetContentHelper(), posOrig );
  439. prstIProp->AcquireContentHelper();
  440. XRestriction xRst( keyRep.AcqRst() );
  441. unsigned pos;
  442. rstAnd->AddChild( xRst.GetPointer(), pos );
  443. xRst.Acquire();
  444. if ( 0 == rstAnd->GetChild( pos ) )
  445. {
  446. prstIProp->SetContentHelper( rstAnd->RemoveChild( posOrig ) );
  447. }
  448. else
  449. {
  450. prstIProp->SetContentHelper( rstAnd.Acquire() );
  451. }
  452. }
  453. }
  454. }
  455. }
  456. }
  457. } //AddLpwstrHelper
  458. //+---------------------------------------------------------------------------
  459. //
  460. // Member: CQParse::AddLpstrHelper, private
  461. //
  462. // Synopsis: Add content helpers for VT_LPSTR properties.
  463. //
  464. // Arguments: [prstProp] -- Property restriction (input)
  465. // [prstIProp] -- Internal property restriction (output)
  466. //
  467. // History: 03-Oct-95 KyleP Broke out as method.
  468. //
  469. //----------------------------------------------------------------------------
  470. void CQParse::AddLpstrHelper( CPropertyRestriction * prstProp,
  471. CInternalPropertyRestriction * prstIProp )
  472. {
  473. //
  474. // For equality, we create a content restriction with GenerateMethod level 0.
  475. //
  476. if ( prstProp->Relation() == PREQ )
  477. {
  478. CQueryKeyRepository keyRep( GENERATE_METHOD_EXACT );
  479. BreakPhrase ( prstProp->Value().GetLPSTR(),
  480. prstProp->GetProperty(),
  481. _lcidSystemDefault,
  482. GENERATE_METHOD_EXACT,
  483. keyRep,
  484. 0,
  485. _pidmap,
  486. _langList );
  487. prstIProp->SetContentHelper( keyRep.AcqRst() );
  488. }
  489. //
  490. // For regular expression, create a GenerateMethod match for any fixed prefix
  491. // on the string.
  492. //
  493. else if ( prstProp->Relation() == PRRE )
  494. {
  495. const MAX_PREFIX_LENGTH = 50;
  496. unsigned i = strcspn( prstProp->Value().GetLPSTR(),
  497. acSpecialRegex );
  498. //
  499. // Should the 0 below be a registry parameter?
  500. //
  501. if ( i > 0 )
  502. {
  503. char ac[MAX_PREFIX_LENGTH];
  504. if ( i > sizeof(ac) - 1 )
  505. i = sizeof(ac) - 1;
  506. memcpy( ac, prstProp->Value().GetLPSTR(), i );
  507. ac[i] = 0;
  508. //
  509. // Trickery: Key repository is GENERATE_METHOD_PREFIX which turns key into ranges.
  510. // Phrase is broken with GENERATE_METHOD_EXACTPREFIXMATCH which does 'exact'
  511. // prefix matching: e.g. it uses the noise word list. The result is
  512. // that we match ranges, but don't set a content helper if we hit
  513. // a noise word. This is different from a user GENERATE_METHOD_PREFIX
  514. // which uses a very minimal noise word list (only 1 character
  515. // prefixes are noise).
  516. //
  517. CQueryKeyRepository keyRep( GENERATE_METHOD_PREFIX );
  518. if ( BP_OK == BreakPhrase ( ac,
  519. prstProp->GetProperty(),
  520. _lcidSystemDefault,
  521. GENERATE_METHOD_EXACTPREFIXMATCH,
  522. keyRep,
  523. 0,
  524. _pidmap,
  525. _langList ) )
  526. {
  527. prstIProp->SetContentHelper( keyRep.AcqRst() );
  528. }
  529. }
  530. }
  531. } //AddLpstrHelper
  532. //+---------------------------------------------------------------------------
  533. //
  534. // Member: CQParse::AddLpwstrVectorHelper, private
  535. //
  536. // Synopsis: Add content helpers for VT_LPWSTR | VT_VECTOR properties.
  537. //
  538. // Arguments: [prstProp] -- Property restriction (input)
  539. // [prstIProp] -- Internal property restriction (output)
  540. //
  541. // History: 03-Oct-95 KyleP Created
  542. //
  543. //----------------------------------------------------------------------------
  544. void CQParse::AddLpwstrVectorHelper( CPropertyRestriction * prstProp,
  545. CInternalPropertyRestriction * prstIProp )
  546. {
  547. if ( prstProp->Value().Count() == 0 )
  548. {
  549. //
  550. // Null vector, hence no helper restriction
  551. //
  552. return;
  553. }
  554. if ( prstProp->Relation() == PREQ || prstProp->Relation() == (PREQ | PRAll) )
  555. {
  556. XNodeRestriction xrstAnd( new CNodeRestriction( RTAnd, prstProp->Value().Count() ) );
  557. Win4Assert( xrstAnd->IsValid() );
  558. for ( unsigned i = 0; i < prstProp->Value().Count(); i++ )
  559. {
  560. CQueryKeyRepository keyRep( GENERATE_METHOD_EXACT );
  561. BreakPhrase ( (WCHAR *)prstProp->Value().GetLPWSTR( i ),
  562. prstProp->GetProperty(),
  563. _lcidSystemDefault,
  564. GENERATE_METHOD_EXACT,
  565. keyRep,
  566. 0,
  567. _pidmap,
  568. _langList );
  569. CRestriction * prst = keyRep.AcqRst();
  570. if ( 0 != prst )
  571. {
  572. XPtr<CRestriction> xRst( prst );
  573. xrstAnd->AddChild( prst );
  574. xRst.Acquire();
  575. }
  576. else
  577. {
  578. _flags |= CI_NOISE_IN_PHRASE;
  579. }
  580. }
  581. //
  582. // If there aren't any nodes (because of noise words) don't set the
  583. // content helper, so we can fall back on enumeration. Set _flags
  584. // in this case so it's obvious why we had to fall back on enumration.
  585. //
  586. if ( xrstAnd->Count() == 1 )
  587. prstIProp->SetContentHelper( xrstAnd->RemoveChild( 0 ) );
  588. else if ( 0 != xrstAnd->Count() )
  589. prstIProp->SetContentHelper( xrstAnd.Acquire() );
  590. }
  591. else if ( prstProp->Relation() == (PREQ | PRAny) )
  592. {
  593. XNodeRestriction xrstOr( new CNodeRestriction( RTOr, prstProp->Value().Count() ) );
  594. for ( unsigned i = 0; i < prstProp->Value().Count(); i++ )
  595. {
  596. CQueryKeyRepository keyRep( GENERATE_METHOD_EXACT );
  597. BreakPhrase ( (WCHAR *)prstProp->Value().GetLPWSTR( i ),
  598. prstProp->GetProperty(),
  599. _lcidSystemDefault,
  600. GENERATE_METHOD_EXACT,
  601. keyRep,
  602. 0,
  603. _pidmap,
  604. _langList );
  605. CRestriction * prst = keyRep.AcqRst();
  606. if ( 0 != prst )
  607. {
  608. XPtr<CRestriction> xRst( prst );
  609. xrstOr->AddChild( prst );
  610. xRst.Acquire();
  611. }
  612. else
  613. break; // If we can't match all OR clauses, then we're in trouble.
  614. }
  615. //
  616. // RTAny is all-or-nothing. A missed clause in one that CI can't resolve, which
  617. // means there are objects that match this query that CI won't find.
  618. //
  619. if ( xrstOr->Count() == prstProp->Value().Count() )
  620. {
  621. if ( xrstOr->Count() == 1 )
  622. prstIProp->SetContentHelper( xrstOr->RemoveChild( 0 ) );
  623. else
  624. prstIProp->SetContentHelper( xrstOr.Acquire() );
  625. }
  626. else
  627. {
  628. _flags |= CI_NOISE_IN_PHRASE;
  629. }
  630. }
  631. } //AddLpwstrVectorHelper
  632. //+---------------------------------------------------------------------------
  633. //
  634. // Function: BreakPhrase
  635. //
  636. // Synopsis: Break phrase into words and noun phrases
  637. //
  638. // Arguments: [phrase] -- string
  639. // [ps] -- property specification
  640. // [GenerateMethod] -- GenerateMethod flag
  641. // [keyRep] -- key repository into which words will be deposited
  642. // [pPhraseSink] -- sink for phrases
  643. // [pidMap] -- pid mapper used to convert property to propid
  644. //
  645. // Returns: Noise word status.
  646. //
  647. // History: 19-Sep-1991 BartoszM Created.
  648. // 18-Jan-1992 KyleP Use restrictions
  649. // 12-Feb-2000 KitmanH Added hack to fix German word breaking
  650. // issue for prefix matching queries
  651. //
  652. //----------------------------------------------------------------------------
  653. BreakPhraseStatus BreakPhrase ( WCHAR const * phrase,
  654. const CFullPropSpec & ps,
  655. LCID lcid,
  656. ULONG GenerateMethod,
  657. PKeyRepository& krep,
  658. IPhraseSink *pPhraseSink,
  659. CPidMapper & pidMap,
  660. CLangList & langList )
  661. {
  662. CDataRepository drep( krep, pPhraseSink, TRUE, GenerateMethod, pidMap, langList );
  663. if ( drep.PutLanguage( lcid ) && drep.PutPropName( ps ) )
  664. {
  665. ciDebugOut (( DEB_ITRACE,
  666. "BreakPhrase: phrase = \"%ws\" Propid = %lu\n",
  667. phrase, drep.GetPropId() ));
  668. drep.PutPhrase( phrase, wcslen(phrase) + 1 );
  669. krep.FixUp( drep );
  670. if ( drep.ContainedNoiseWords() )
  671. return BP_NOISE;
  672. else
  673. return BP_OK;
  674. }
  675. else
  676. return BP_INVALID_PROPERTY;
  677. } //BreakPhrase
  678. //
  679. // DBCS version of the previous function.
  680. //
  681. BreakPhraseStatus BreakPhrase ( char const * phrase,
  682. const CFullPropSpec & ps,
  683. LCID lcid,
  684. ULONG GenerateMethod,
  685. PKeyRepository& krep,
  686. IPhraseSink *pPhraseSink,
  687. CPidMapper & pidMap,
  688. CLangList & langList )
  689. {
  690. CDataRepository drep( krep, pPhraseSink, TRUE, GenerateMethod, pidMap, langList );
  691. if ( drep.PutLanguage( lcid ) && drep.PutPropName( ps ) )
  692. {
  693. ciDebugOut (( DEB_ITRACE,
  694. "BreakPhrase: phrase = \"%s\" Propid = %lu\n",
  695. phrase, drep.GetPropId() ));
  696. drep.PutPhrase( phrase, strlen(phrase) + 1 );
  697. krep.FixUp( drep );
  698. if ( drep.ContainedNoiseWords() )
  699. return BP_NOISE;
  700. else
  701. return BP_OK;
  702. }
  703. else
  704. return BP_INVALID_PROPERTY;
  705. } //BreakPhrase