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.

897 lines
24 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: pidtable.cxx
  7. //
  8. // Contents: Property to PROPID mapping table
  9. //
  10. // History: 02 Jan 1996 AlanW Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <rcstxact.hxx>
  16. #include <rcstrmit.hxx>
  17. #include <pidtable.hxx>
  18. #include <imprsnat.hxx>
  19. const ULONG PIDTAB_INIT_HASH_SIZE = 17;
  20. const ULONG MEASURE_OF_SLACK = 4; // 80% full maximum
  21. //
  22. // cchNamePart - number of WCHARs that will fit into a CPidLookupEntry
  23. //
  24. const unsigned cchNamePart = sizeof (CPidLookupEntry) / sizeof (WCHAR);
  25. //+-------------------------------------------------------------------------
  26. //
  27. // Method: CPidLookupTable::CPidLookupTable, public
  28. //
  29. // Synopsis: Constructor of a CPidLookupTable
  30. //
  31. // Arguments: -NONE-
  32. //
  33. // Returns: Nothing
  34. //
  35. //--------------------------------------------------------------------------
  36. CPidLookupTable::CPidLookupTable( )
  37. : _pTable( 0 ),
  38. _pchStringBase( 0 ),
  39. _cbStrings( 0 ),
  40. _cbStringUsed( 0 ),
  41. #if !defined(UNIT_TEST)
  42. _xrsoPidTable( 0 ),
  43. #endif // !defined(UNIT_TEST)
  44. _mutex()
  45. {
  46. #if (DBG == 1)
  47. _iFillFactor = (100 * MEASURE_OF_SLACK) / (MEASURE_OF_SLACK + 1);
  48. #endif // (DBG == 1)
  49. }
  50. void CPidLookupTable::Empty()
  51. {
  52. delete [] _pTable; _pTable = 0;
  53. delete [] _pchStringBase; _pchStringBase = 0;
  54. _cbStrings = _cbStringUsed = 0;
  55. #if !defined(UNIT_TEST)
  56. delete _xrsoPidTable.Acquire();
  57. #endif // UNIT_TEST
  58. }
  59. CPidLookupTable::~CPidLookupTable( )
  60. {
  61. delete [] _pchStringBase;
  62. delete [] _pTable;
  63. }
  64. //+-------------------------------------------------------------------------
  65. //
  66. // Method: CPidLookupTable::Init, public
  67. //
  68. // Synopsis: Initialize a CPidLookupTable
  69. //
  70. // Arguments: [cHash] - number of hash buckets to allocate
  71. //
  72. // Returns: Nothing
  73. //
  74. //--------------------------------------------------------------------------
  75. void CPidLookupTable::Init( ULONG cHash )
  76. {
  77. Win4Assert( _pTable == 0 );
  78. if ( cHash == 0 )
  79. {
  80. RtlCopyMemory( _Header.Signature, "PIDTABLE", sizeof _Header.Signature );
  81. _Header.cbRecord = sizeof (CPidLookupEntry);
  82. _Header.NextPropid = INIT_DOWNLEVEL_PID;
  83. cHash = PIDTAB_INIT_HASH_SIZE;
  84. }
  85. _pTable = new CPidLookupEntry [ cHash ];
  86. RtlZeroMemory( _pTable, cHash * sizeof (CPidLookupEntry) );
  87. _Header.cHash = cHash;
  88. _Header.cEntries = 0;
  89. #if (DBG == 1)
  90. Win4Assert( _iFillFactor > 10 && _iFillFactor <= 95);
  91. _maxEntries = (Size() * _iFillFactor) / 100;
  92. _cMaxChainLen = 0;
  93. _cTotalSearches = 0;
  94. _cTotalLength = 0;
  95. #else // (DBG != 1)
  96. _maxEntries = (Size() * MEASURE_OF_SLACK) / (MEASURE_OF_SLACK + 1);
  97. #endif // (DBG == 1)
  98. Win4Assert(_maxEntries >= 5 && _maxEntries < Size());
  99. }
  100. #if !defined(UNIT_TEST)
  101. //+---------------------------------------------------------------------------
  102. //
  103. // Member: CPidLookupTable::Init, public
  104. //
  105. // Synopsis: Loads metadata from persistent location into memory.
  106. //
  107. // Arguments: [pobj] -- Stream(s) in which metadata is stored.
  108. //
  109. // History: 27-Dec-95 KyleP Created.
  110. //
  111. //----------------------------------------------------------------------------
  112. BOOL CPidLookupTable::Init( PRcovStorageObj * pObj )
  113. {
  114. CLock lock ( _mutex );
  115. _xrsoPidTable.Set( pObj );
  116. //
  117. // Load header
  118. //
  119. CRcovStorageHdr & hdr = _xrsoPidTable->GetHeader();
  120. struct CRcovUserHdr data;
  121. hdr.GetUserHdr( hdr.GetPrimary(), data );
  122. RtlCopyMemory( &_Header, &data._abHdr, sizeof(_Header) );
  123. ciDebugOut(( DEB_PIDTABLE, "PIDTABLE: Record size = %d bytes\n", _Header.cbRecord ));
  124. ciDebugOut(( DEB_PIDTABLE, "PIDTABLE: %d properties stored\n", _Header.cEntries ));
  125. ciDebugOut(( DEB_PIDTABLE, "PIDTABLE: Hash size = %u\n", _Header.cHash ));
  126. ciDebugOut(( DEB_PIDTABLE, "PIDTABLE: Next Propid = %u\n", _Header.NextPropid ));
  127. if (_Header.cbRecord != 0)
  128. {
  129. Win4Assert( RtlEqualMemory( _Header.Signature, "PIDTABLE",
  130. sizeof _Header.Signature) &&
  131. _Header.cbRecord == sizeof (CPidLookupEntry) &&
  132. Entries() < Size() );
  133. if ( !RtlEqualMemory( _Header.Signature, "PIDTABLE",
  134. sizeof _Header.Signature) ||
  135. _Header.cbRecord != sizeof (CPidLookupEntry) ||
  136. Entries() >= Size()
  137. )
  138. return FALSE;
  139. }
  140. else
  141. {
  142. Win4Assert( 0 == Entries() && 0 == Size() );
  143. }
  144. //
  145. // Load properties
  146. //
  147. ULONG cEntriesFromFile = Entries();
  148. Init( _Header.cHash );
  149. CRcovStrmReadTrans xact( _xrsoPidTable.GetReference() );
  150. CRcovStrmReadIter iter( xact, sizeof( CPidLookupEntry ) );
  151. CPidLookupEntry temp;
  152. while ( !iter.AtEnd() )
  153. {
  154. iter.GetRec( &temp );
  155. if ( temp.IsPropertyName() )
  156. {
  157. temp.SetPropertyNameOffset( _cbStringUsed / sizeof (WCHAR) );
  158. Win4Assert( !iter.AtEnd() );
  159. BYTE* pPropName;
  160. ULONG cbName = iter.GetVariableRecSize();
  161. if ( _cbStringUsed + cbName > _cbStrings )
  162. GrowStringSpace( cbName );
  163. iter.GetVariableRecData( (void*)&_pchStringBase[_cbStringUsed / sizeof (WCHAR)],
  164. cbName );
  165. _cbStringUsed += cbName;
  166. ciDebugOut(( DEB_PIDTABLE,
  167. "PIDTABLE: Named property\tpid = 0x%x, %ws\n",
  168. temp.Pid(),
  169. temp.GetPropertyNameOffset() + _pchStringBase ));
  170. if (cbName == 0 || cbName > MAX_PROPERTY_NAME_LEN)
  171. {
  172. ciDebugOut(( DEB_WARN,
  173. "PIDTABLE: Invalid named property\tpid = 0x%x, %ws\n",
  174. temp.Pid(),
  175. temp.GetPropertyNameOffset() + _pchStringBase ));
  176. return FALSE;
  177. }
  178. }
  179. else
  180. {
  181. ciDebugOut(( DEB_PIDTABLE,
  182. "PIDTABLE: Numbered property\tpid = 0x%x, propid = %u\n",
  183. temp.Pid(),
  184. temp.GetPropertyPropid() ));
  185. Win4Assert ( temp.IsPropertyPropid() );
  186. if ( ! temp.IsPropertyPropid() )
  187. return FALSE;
  188. }
  189. if ( temp.Pid() < INIT_DOWNLEVEL_PID )
  190. {
  191. ciDebugOut(( DEB_WARN,
  192. "PIDTABLE: Invalid propid\tpid = 0x%x\n",
  193. temp.Pid() ));
  194. return FALSE;
  195. }
  196. StoreInTable(temp);
  197. }
  198. Win4Assert( Entries() == cEntriesFromFile );
  199. return TRUE;
  200. }
  201. #endif // !defined(UNIT_TEST)
  202. //+---------------------------------------------------------------------------
  203. //
  204. // Member: CPidLookupTable::MakeBackupCopy
  205. //
  206. // Synopsis: Makes a backup copy of the persistent pid table.
  207. //
  208. // Arguments: [dstObj] - Destination object.
  209. // [tracker] - Save progress tracker.
  210. //
  211. // History: 3-20-97 srikants Created
  212. //
  213. //----------------------------------------------------------------------------
  214. void CPidLookupTable::MakeBackupCopy( PRcovStorageObj & dstObj,
  215. PSaveProgressTracker & tracker )
  216. {
  217. Win4Assert( !_xrsoPidTable.IsNull() );
  218. CCopyRcovObject copier( dstObj, _xrsoPidTable.GetReference() );
  219. copier.DoIt();
  220. }
  221. //+-------------------------------------------------------------------------
  222. //
  223. // Method: CPidLookupTable::Hash, private
  224. //
  225. // Synopsis: Hash a CFullPropSpec value for use in a hash table.
  226. //
  227. // Arguments: [rProp] - a reference to the CFullPropSpec to be hashed
  228. //
  229. // Returns: ULONG - Hash value for the input CFullPropSpec
  230. //
  231. // Notes: The hash function xors only a few selected fields out
  232. // of the GUID structure. It is intended to work well for
  233. // both generated GUIDs (from UuidCreate) and administratively
  234. // assigned GUIDs.
  235. //
  236. //--------------------------------------------------------------------------
  237. ULONG CPidLookupTable::Hash(
  238. const CFullPropSpec & rProp )
  239. {
  240. const GUID & rGuid = rProp.GetPropSet();
  241. ULONG ulHash = (rGuid.Data1 ^
  242. (rGuid.Data4[0] << 16) ^
  243. (rGuid.Data4[6] << 8) ^
  244. (rGuid.Data4[7]));
  245. if (rProp.IsPropertyPropid())
  246. {
  247. ulHash ^= (1 << 24) | rProp.GetPropertyPropid();
  248. }
  249. else
  250. {
  251. ulHash ^= HashString(rProp.GetPropertyName());
  252. }
  253. return ulHash;
  254. }
  255. //+-------------------------------------------------------------------------
  256. //
  257. // Method: CPidLookupTable::Hash, private
  258. //
  259. // Synopsis: Hash a CPidLookupEntry value (for rehashing)
  260. //
  261. // Arguments: [rProp] - a reference to the CPidLookupEntry to be hashed
  262. //
  263. // Returns: ULONG - Hash value for the input CPidLookupEntry
  264. //
  265. // Notes: The hash function xors only a few selected fields out
  266. // of the GUID structure. It is intended to work well for
  267. // both generated GUIDs (from UuidCreate) and administratively
  268. // assigned GUIDs.
  269. //
  270. //--------------------------------------------------------------------------
  271. ULONG CPidLookupTable::Hash(
  272. const CPidLookupEntry & rProp )
  273. {
  274. const GUID & rGuid = rProp.GetPropSet();
  275. ULONG ulHash = (rGuid.Data1 ^
  276. (rGuid.Data4[0] << 16) ^
  277. (rGuid.Data4[6] << 8) ^
  278. (rGuid.Data4[7]));
  279. if (rProp.IsPropertyPropid())
  280. {
  281. ulHash ^= (1 << 24) | rProp.GetPropertyPropid();
  282. }
  283. else
  284. {
  285. const WCHAR * pwszStr = rProp.GetPropertyNameOffset() +
  286. _pchStringBase;
  287. ulHash ^= HashString(pwszStr);
  288. }
  289. return ulHash;
  290. }
  291. //+-------------------------------------------------------------------------
  292. //
  293. // Method: CPidLookupTable::HashString, private
  294. //
  295. // Synopsis: Hash a string from a property name.
  296. //
  297. // Arguments: [pwszStr] - the string to be hashed
  298. //
  299. // Returns: ULONG - Hash value for the input string
  300. //
  301. // Notes: Property names are assumed to be mapped to lower case.
  302. //
  303. //--------------------------------------------------------------------------
  304. ULONG CPidLookupTable::HashString( const WCHAR * pwszStr )
  305. {
  306. ULONG ulStrHash = 0;
  307. while ( *pwszStr != L'\0' )
  308. {
  309. ulStrHash = (ulStrHash << 1) ^ (*pwszStr++);
  310. }
  311. return ulStrHash;
  312. }
  313. //+---------------------------------------------------------------------------
  314. //
  315. // Method: CPidLookupTable::LookUp, private
  316. //
  317. // Synopsis: Looks up a property in the hash table.
  318. //
  319. // Arguments: [Prop] - Property to look up.
  320. // [riTable] - (output) Will contain the index in the hash
  321. // table of the entry if found.
  322. //
  323. // Returns: TRUE if found; FALSE o/w
  324. //
  325. // History: 02 Jan 1996 Alanw Created
  326. //
  327. // Notes: On failure, riTable will point to an empty entry.
  328. //
  329. //----------------------------------------------------------------------------
  330. BOOL CPidLookupTable::LookUp( const CFullPropSpec & Prop, ULONG &riTable )
  331. {
  332. Win4Assert( 0 != Size() );
  333. Win4Assert( !IsFull() );
  334. ULONG iCur = Hash( Prop ) % Size();
  335. ULONG iStart = iCur;
  336. ULONG iDelta = iCur;
  337. #if DBG==1
  338. ULONG cSearchLen = 1;
  339. #endif // DBG==1
  340. BOOL fFound = FALSE;
  341. while ( !fFound && ! _pTable[iCur].IsFree() )
  342. {
  343. if ( _pTable[iCur].IsEqual( Prop, _pchStringBase ) )
  344. {
  345. fFound = TRUE;
  346. }
  347. else
  348. {
  349. iCur = (iCur + iDelta) % Size();
  350. if ( iCur == iStart ) // wrapped around
  351. {
  352. if ( 1 != iDelta )
  353. {
  354. iDelta = 1;
  355. iCur = (iCur + 1) % Size();
  356. }
  357. else
  358. {
  359. Win4Assert( ! "Failed to find empty hash table entry" );
  360. break;
  361. }
  362. }
  363. #if DBG==1
  364. cSearchLen++;
  365. #endif // DBG==1
  366. }
  367. }
  368. #if DBG==1
  369. _cTotalSearches++;
  370. _cTotalLength += cSearchLen;
  371. if (cSearchLen > _cMaxChainLen)
  372. _cMaxChainLen = cSearchLen;
  373. #endif // DBG==1
  374. riTable = iCur;
  375. if (!fFound)
  376. {
  377. Win4Assert( _pTable[iCur].IsFree() );
  378. }
  379. return fFound;
  380. }
  381. //+---------------------------------------------------------------------------
  382. //
  383. // Method: CPidLookupTable::StoreInTable, private
  384. //
  385. // Synopsis: Stores a CPidLookupEntry in the hash table.
  386. //
  387. // Arguments: [Prop] - Property to store; must not be in the table
  388. //
  389. // Returns: NOTHING
  390. //
  391. // History: 02 Jan 1996 Alanw Created
  392. //
  393. // Notes: This function is used in rehashing and the initial load of
  394. // the table. It is not expected to find the property, but it
  395. // returns the slot in which the entry should be placed.
  396. //
  397. //----------------------------------------------------------------------------
  398. void CPidLookupTable::StoreInTable( const CPidLookupEntry & Prop )
  399. {
  400. Win4Assert( 0 != Size() );
  401. Win4Assert( !IsFull() );
  402. ULONG iCur = Hash( Prop ) % Size();
  403. ULONG iStart = iCur;
  404. ULONG iDelta = iCur;
  405. #if DBG==1
  406. ULONG cSearchLen = 1;
  407. #endif // DBG==1
  408. while ( ! _pTable[iCur].IsFree() )
  409. {
  410. #if DBG==1
  411. if (Prop.IsPropertyPropid())
  412. {
  413. Win4Assert( !_pTable[iCur].IsPropertyPropid() ||
  414. Prop.GetPropertyPropid() != _pTable[iCur].GetPropertyPropid() ||
  415. Prop.GetPropSet() != _pTable[iCur].GetPropSet());
  416. }
  417. else
  418. {
  419. Win4Assert( !_pTable[iCur].IsPropertyName() ||
  420. Prop.GetPropSet() != _pTable[iCur].GetPropSet() ||
  421. _wcsicmp( Prop.GetPropertyNameOffset() +
  422. _pchStringBase,
  423. _pTable[iCur].GetPropertyNameOffset() +
  424. _pchStringBase) != 0);
  425. }
  426. #endif // DBG==1
  427. iCur = (iCur + iDelta) % Size();
  428. if ( iCur == iStart ) // wrapped around
  429. {
  430. if ( 1 != iDelta )
  431. {
  432. iDelta = 1;
  433. iCur = (iCur + 1) % Size();
  434. }
  435. else
  436. {
  437. Win4Assert( ! "Failed to find empty hash table entry" );
  438. break;
  439. }
  440. }
  441. #if DBG==1
  442. cSearchLen++;
  443. #endif // DBG==1
  444. }
  445. #if DBG==1
  446. if (cSearchLen > _cMaxChainLen)
  447. _cMaxChainLen = cSearchLen;
  448. #endif // DBG==1
  449. _pTable[iCur] = Prop;
  450. _Header.cEntries++;
  451. }
  452. //+---------------------------------------------------------------------------
  453. //
  454. // Method: CPidLookupTable::GrowSize, private
  455. //
  456. // Synopsis: For a given valid hash table entries, this routine figures
  457. // out the next valid size (close approximation to a prime).
  458. //
  459. // Arguments: - NONE -
  460. //
  461. // Returns: The size of the hash table for the given number of valid
  462. // entries.
  463. //
  464. // History: 1-09-95 srikants Created
  465. //
  466. // Notes:
  467. //
  468. //----------------------------------------------------------------------------
  469. ULONG CPidLookupTable::GrowSize ( void ) const
  470. {
  471. ULONG size = Size() + 2;
  472. for (unsigned i = 0; i < g_cPrimes && g_aPrimes[i] < size; i++)
  473. ;
  474. if (i < g_cPrimes)
  475. return g_aPrimes[i];
  476. // make it power of two - 1
  477. // a good approximation of a prime
  478. for ( unsigned sizeInit = 1; sizeInit < size; sizeInit *= 2 )
  479. continue;
  480. return (sizeInit - 1);
  481. } //GrowSize
  482. //+---------------------------------------------------------------------------
  483. //
  484. // Method: CPidLookupTable::AddEntry, private
  485. //
  486. // Synopsis: Adds a property entry in the hash table.
  487. //
  488. // Arguments: [Prop] - Property to Add
  489. //
  490. // Returns: ULONG - the index of the entry used to store the property
  491. //
  492. // History: 02 Jan 1996 Alanw Created
  493. //
  494. // Notes: It is assumed that the entry does not already exist in the
  495. // table. The input property spec has already been normalized
  496. // and checked for error.
  497. //
  498. //----------------------------------------------------------------------------
  499. ULONG CPidLookupTable::AddEntry( const CFullPropSpec & Prop )
  500. {
  501. if (Size() == 0 ||
  502. Entries() >= _maxEntries)
  503. {
  504. GrowAndRehash( GrowSize() );
  505. }
  506. ULONG cbNameLength = 0;
  507. if (Prop.IsPropertyName())
  508. {
  509. cbNameLength = ( wcslen(Prop.GetPropertyName()) + 1) * sizeof (WCHAR);
  510. //
  511. // Check for a bogus null property name
  512. //
  513. Win4Assert( cbNameLength > sizeof (WCHAR) );
  514. Win4Assert( cbNameLength <= MAX_PROPERTY_NAME_LEN );
  515. if (_cbStringUsed + cbNameLength > _cbStrings)
  516. {
  517. GrowStringSpace( cbNameLength );
  518. }
  519. }
  520. ULONG iEntry = ~0u;
  521. BOOL fFound = LookUp( Prop, iEntry );
  522. Win4Assert( fFound == FALSE && iEntry < Size() &&
  523. _pTable[iEntry].IsFree() );
  524. _pTable[iEntry].SetPropSet( Prop.GetPropSet() );
  525. if ( Prop.IsPropertyPropid() )
  526. {
  527. _pTable[iEntry].SetPropertyPropid( Prop.GetPropertyPropid() );
  528. }
  529. else
  530. {
  531. WCHAR * pchName = _pchStringBase + (_cbStringUsed / sizeof (WCHAR));
  532. RtlCopyMemory( pchName, Prop.GetPropertyName(), cbNameLength );
  533. _cbStringUsed += cbNameLength;
  534. _pTable[iEntry].SetPropertyNameOffset( (ULONG)(pchName - _pchStringBase) );
  535. Win4Assert( _cbStringUsed <= _cbStrings );
  536. }
  537. _pTable[iEntry].SetPid( NextPropid() );
  538. _Header.NextPropid++;
  539. _Header.cEntries++;
  540. #if !defined(UNIT_TEST)
  541. //
  542. // Write new mapping to the recoverable storage
  543. //
  544. CRcovStorageHdr & hdr = _xrsoPidTable->GetHeader();
  545. CRcovStrmAppendTrans xact( _xrsoPidTable.GetReference() );
  546. CRcovStrmAppendIter iter( xact, sizeof (CPidLookupEntry) );
  547. iter.AppendRec( &_pTable[iEntry] );
  548. ULONG cRecordsWritten = 1;
  549. if (cbNameLength)
  550. {
  551. iter.AppendVariableRec( Prop.GetPropertyName(), cbNameLength );
  552. cRecordsWritten++;
  553. }
  554. struct CRcovUserHdr data;
  555. RtlCopyMemory( &data._abHdr, &_Header, sizeof(_Header) );
  556. Win4Assert( hdr.GetCount(hdr.GetBackup()) == hdr.GetCount(hdr.GetPrimary()) + cRecordsWritten);
  557. hdr.SetUserHdr( hdr.GetBackup(), data );
  558. xact.Commit();
  559. #endif // !defined(UNIT_TEST)
  560. return iEntry;
  561. }
  562. //+-------------------------------------------------------------------------
  563. //
  564. // Method: CPidLookupTable::GrowAndRehash, private
  565. //
  566. // Synopsis: Grow the hash table in a CPidLookupTable
  567. //
  568. // Arguments: [cNewHash] - number of hash buckets to allocate
  569. //
  570. // Returns: Nothing
  571. //
  572. //--------------------------------------------------------------------------
  573. void CPidLookupTable::GrowAndRehash( ULONG cNewHash )
  574. {
  575. Win4Assert( cNewHash > Size() );
  576. ULONG cOldSize = Size();
  577. ULONG cOldEntries = Entries();
  578. XPtr<CPidLookupEntry> pOldTable( _pTable );
  579. _pTable = 0;
  580. Init( cNewHash );
  581. for (unsigned i = 0; i < cOldSize; i++)
  582. {
  583. if ((pOldTable.GetPointer() + i)->IsFree())
  584. continue;
  585. StoreInTable( *(pOldTable.GetPointer() + i) );
  586. }
  587. Win4Assert( Entries() < Size() && Entries() < _maxEntries );
  588. Win4Assert( Entries() == cOldEntries );
  589. }
  590. //+-------------------------------------------------------------------------
  591. //
  592. // Method: CPidLookupTable::GrowStringSpace, private
  593. //
  594. // Synopsis: Grow the string space in a CPidLookupTable
  595. //
  596. // Arguments: [cbNewString] - size (in bytes) to reserve for new string
  597. //
  598. // Returns: Nothing
  599. //
  600. //--------------------------------------------------------------------------
  601. void CPidLookupTable::GrowStringSpace( ULONG cbNewString )
  602. {
  603. ULONG cbNew = _cbStringUsed + 2*cbNewString;
  604. Win4Assert( cbNew > _cbStrings );
  605. WCHAR * pchNew = new WCHAR[ cbNew/sizeof (WCHAR) ];
  606. if ( 0 != _cbStringUsed )
  607. {
  608. RtlCopyMemory( pchNew, _pchStringBase, _cbStringUsed );
  609. delete [] _pchStringBase;
  610. }
  611. _pchStringBase = pchNew;
  612. _cbStrings = cbNew;
  613. }
  614. //+---------------------------------------------------------------------------
  615. //
  616. // Method: CPidLookupTable::FindPropid, public
  617. //
  618. // Synopsis: Looks up a property entry in the hash table.
  619. //
  620. // Arguments: [Prop] - Property to lookup
  621. // [rPid] - Propid found
  622. // [fAddToTable] - If TRUE, add Prop to table if it was not
  623. // found.
  624. //
  625. // Returns: BOOL - TRUE if Prop was found or successfully added.
  626. //
  627. // History: 02 Jan 1996 Alanw Created
  628. //
  629. // Notes:
  630. //
  631. //----------------------------------------------------------------------------
  632. BOOL CPidLookupTable::FindPropid( const CFullPropSpec & InputProp,
  633. PROPID & rPid,
  634. BOOL fAddToTable )
  635. {
  636. rPid = pidInvalid;
  637. ULONG cbNameLength = 0;
  638. CFullPropSpec Prop;
  639. if (InputProp.IsPropertyPropid())
  640. {
  641. Win4Assert( InputProp.GetPropertyPropid() != PID_DICTIONARY &&
  642. InputProp.GetPropertyPropid() != PID_CODEPAGE );
  643. if (InputProp.GetPropertyPropid() <= PID_CODEPAGE )
  644. return FALSE;
  645. Prop = InputProp;
  646. }
  647. else
  648. {
  649. // map the input property name to lower case
  650. Win4Assert( InputProp.IsPropertyName() );
  651. if ( InputProp.GetPropertyName() == 0 ||
  652. *InputProp.GetPropertyName() == L'\0' )
  653. {
  654. Win4Assert( !"CPidLookupTable - bad named property!" );
  655. return FALSE;
  656. }
  657. CLowcaseBuf wcsBuf( InputProp.GetPropertyName() );
  658. cbNameLength = (wcsBuf.Length() + 1) * sizeof (WCHAR);
  659. if ( cbNameLength >= MAX_PROPERTY_NAME_LEN )
  660. {
  661. ciDebugOut(( DEB_WARN,
  662. "PIDTABLE: long named property truncated\t%ws\n",
  663. InputProp.GetPropertyName() ));
  664. // Truncate the property name if it's too long.
  665. cbNameLength = MAX_PROPERTY_NAME_LEN;
  666. (wcsBuf.GetWriteable())[(cbNameLength/sizeof(WCHAR))-1] = L'\0';
  667. }
  668. //
  669. // It would be nice if we could just use the lower-cased string
  670. // from the CLowcaseBuf directly, but it's about to go out of scope.
  671. //
  672. Prop.SetPropSet( InputProp.GetPropSet() );
  673. Prop.SetProperty( wcsBuf.Get( ) );
  674. if ( !Prop.IsValid() )
  675. THROW( CException( E_OUTOFMEMORY ) );
  676. }
  677. if ( !Prop.IsValid() )
  678. return FALSE;
  679. CLock lock ( _mutex );
  680. ULONG iEntry = ~0u;
  681. BOOL fFound = LookUp( Prop, iEntry );
  682. if ( ! fFound && fAddToTable )
  683. {
  684. CImpersonateSystem impersonate;
  685. iEntry = AddEntry( Prop );
  686. fFound = TRUE;
  687. }
  688. if (fFound)
  689. {
  690. rPid = _pTable[iEntry].Pid();
  691. Win4Assert( iEntry < Size() && ! _pTable[iEntry].IsFree() );
  692. }
  693. return fFound;
  694. } //FindPropid
  695. //+---------------------------------------------------------------------------
  696. //
  697. // Method: CPidLookupTable::EnumerateProperty, public
  698. //
  699. // Synopsis: Enumerate properties in the property list
  700. //
  701. // Arguments: [ps] -- Full PropSpec returned here
  702. // [iBmk] -- Bookmark. Initialized to 0 before first call.
  703. //
  704. // Returns: BOOL equivalent: PROPID, 0 if at the end of the enumeration.
  705. //
  706. // History: 20-Jun-1996 KyleP Created
  707. //
  708. //----------------------------------------------------------------------------
  709. BOOL CPidLookupTable::EnumerateProperty( CFullPropSpec & ps, unsigned & iBmk )
  710. {
  711. for ( ; iBmk < Size() && _pTable[iBmk].IsFree(); iBmk++ )
  712. continue;
  713. PROPID pid = 0;
  714. if ( iBmk >= Size() )
  715. return 0;
  716. ps.SetPropSet( _pTable[iBmk].GetPropSet() );
  717. if ( _pTable[iBmk].IsPropertyPropid() )
  718. ps.SetProperty( _pTable[iBmk].GetPropertyPropid() );
  719. else
  720. {
  721. ps.SetProperty( _pTable[iBmk].GetPropertyNameOffset() + _pchStringBase );
  722. if ( !ps.IsValid() )
  723. THROW( CException( E_OUTOFMEMORY ) );
  724. }
  725. pid = _pTable[iBmk].Pid();
  726. iBmk++;
  727. return pid;
  728. } //EnumerateProperty