898 lines
24 KiB
C++
898 lines
24 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1996 - 2000.
|
||
|
//
|
||
|
// File: pidtable.cxx
|
||
|
//
|
||
|
// Contents: Property to PROPID mapping table
|
||
|
//
|
||
|
// History: 02 Jan 1996 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.cxx>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <rcstxact.hxx>
|
||
|
#include <rcstrmit.hxx>
|
||
|
#include <pidtable.hxx>
|
||
|
#include <imprsnat.hxx>
|
||
|
|
||
|
|
||
|
const ULONG PIDTAB_INIT_HASH_SIZE = 17;
|
||
|
const ULONG MEASURE_OF_SLACK = 4; // 80% full maximum
|
||
|
|
||
|
//
|
||
|
// cchNamePart - number of WCHARs that will fit into a CPidLookupEntry
|
||
|
//
|
||
|
const unsigned cchNamePart = sizeof (CPidLookupEntry) / sizeof (WCHAR);
|
||
|
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::CPidLookupTable, public
|
||
|
//
|
||
|
// Synopsis: Constructor of a CPidLookupTable
|
||
|
//
|
||
|
// Arguments: -NONE-
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
CPidLookupTable::CPidLookupTable( )
|
||
|
: _pTable( 0 ),
|
||
|
_pchStringBase( 0 ),
|
||
|
_cbStrings( 0 ),
|
||
|
_cbStringUsed( 0 ),
|
||
|
#if !defined(UNIT_TEST)
|
||
|
_xrsoPidTable( 0 ),
|
||
|
#endif // !defined(UNIT_TEST)
|
||
|
_mutex()
|
||
|
{
|
||
|
#if (DBG == 1)
|
||
|
_iFillFactor = (100 * MEASURE_OF_SLACK) / (MEASURE_OF_SLACK + 1);
|
||
|
#endif // (DBG == 1)
|
||
|
}
|
||
|
|
||
|
|
||
|
void CPidLookupTable::Empty()
|
||
|
{
|
||
|
delete [] _pTable; _pTable = 0;
|
||
|
|
||
|
delete [] _pchStringBase; _pchStringBase = 0;
|
||
|
_cbStrings = _cbStringUsed = 0;
|
||
|
|
||
|
#if !defined(UNIT_TEST)
|
||
|
delete _xrsoPidTable.Acquire();
|
||
|
#endif // UNIT_TEST
|
||
|
|
||
|
}
|
||
|
|
||
|
CPidLookupTable::~CPidLookupTable( )
|
||
|
{
|
||
|
delete [] _pchStringBase;
|
||
|
delete [] _pTable;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::Init, public
|
||
|
//
|
||
|
// Synopsis: Initialize a CPidLookupTable
|
||
|
//
|
||
|
// Arguments: [cHash] - number of hash buckets to allocate
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CPidLookupTable::Init( ULONG cHash )
|
||
|
{
|
||
|
Win4Assert( _pTable == 0 );
|
||
|
|
||
|
if ( cHash == 0 )
|
||
|
{
|
||
|
RtlCopyMemory( _Header.Signature, "PIDTABLE", sizeof _Header.Signature );
|
||
|
_Header.cbRecord = sizeof (CPidLookupEntry);
|
||
|
_Header.NextPropid = INIT_DOWNLEVEL_PID;
|
||
|
cHash = PIDTAB_INIT_HASH_SIZE;
|
||
|
}
|
||
|
|
||
|
_pTable = new CPidLookupEntry [ cHash ];
|
||
|
|
||
|
RtlZeroMemory( _pTable, cHash * sizeof (CPidLookupEntry) );
|
||
|
|
||
|
_Header.cHash = cHash;
|
||
|
_Header.cEntries = 0;
|
||
|
|
||
|
#if (DBG == 1)
|
||
|
Win4Assert( _iFillFactor > 10 && _iFillFactor <= 95);
|
||
|
|
||
|
_maxEntries = (Size() * _iFillFactor) / 100;
|
||
|
|
||
|
_cMaxChainLen = 0;
|
||
|
_cTotalSearches = 0;
|
||
|
_cTotalLength = 0;
|
||
|
#else // (DBG != 1)
|
||
|
_maxEntries = (Size() * MEASURE_OF_SLACK) / (MEASURE_OF_SLACK + 1);
|
||
|
|
||
|
#endif // (DBG == 1)
|
||
|
|
||
|
Win4Assert(_maxEntries >= 5 && _maxEntries < Size());
|
||
|
}
|
||
|
|
||
|
|
||
|
#if !defined(UNIT_TEST)
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CPidLookupTable::Init, public
|
||
|
//
|
||
|
// Synopsis: Loads metadata from persistent location into memory.
|
||
|
//
|
||
|
// Arguments: [pobj] -- Stream(s) in which metadata is stored.
|
||
|
//
|
||
|
// History: 27-Dec-95 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CPidLookupTable::Init( PRcovStorageObj * pObj )
|
||
|
{
|
||
|
CLock lock ( _mutex );
|
||
|
|
||
|
_xrsoPidTable.Set( pObj );
|
||
|
|
||
|
//
|
||
|
// Load header
|
||
|
//
|
||
|
|
||
|
CRcovStorageHdr & hdr = _xrsoPidTable->GetHeader();
|
||
|
struct CRcovUserHdr data;
|
||
|
hdr.GetUserHdr( hdr.GetPrimary(), data );
|
||
|
|
||
|
RtlCopyMemory( &_Header, &data._abHdr, sizeof(_Header) );
|
||
|
|
||
|
ciDebugOut(( DEB_PIDTABLE, "PIDTABLE: Record size = %d bytes\n", _Header.cbRecord ));
|
||
|
ciDebugOut(( DEB_PIDTABLE, "PIDTABLE: %d properties stored\n", _Header.cEntries ));
|
||
|
ciDebugOut(( DEB_PIDTABLE, "PIDTABLE: Hash size = %u\n", _Header.cHash ));
|
||
|
ciDebugOut(( DEB_PIDTABLE, "PIDTABLE: Next Propid = %u\n", _Header.NextPropid ));
|
||
|
|
||
|
if (_Header.cbRecord != 0)
|
||
|
{
|
||
|
Win4Assert( RtlEqualMemory( _Header.Signature, "PIDTABLE",
|
||
|
sizeof _Header.Signature) &&
|
||
|
_Header.cbRecord == sizeof (CPidLookupEntry) &&
|
||
|
Entries() < Size() );
|
||
|
if ( !RtlEqualMemory( _Header.Signature, "PIDTABLE",
|
||
|
sizeof _Header.Signature) ||
|
||
|
_Header.cbRecord != sizeof (CPidLookupEntry) ||
|
||
|
Entries() >= Size()
|
||
|
)
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Win4Assert( 0 == Entries() && 0 == Size() );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Load properties
|
||
|
//
|
||
|
|
||
|
ULONG cEntriesFromFile = Entries();
|
||
|
Init( _Header.cHash );
|
||
|
|
||
|
CRcovStrmReadTrans xact( _xrsoPidTable.GetReference() );
|
||
|
CRcovStrmReadIter iter( xact, sizeof( CPidLookupEntry ) );
|
||
|
|
||
|
CPidLookupEntry temp;
|
||
|
|
||
|
while ( !iter.AtEnd() )
|
||
|
{
|
||
|
iter.GetRec( &temp );
|
||
|
|
||
|
if ( temp.IsPropertyName() )
|
||
|
{
|
||
|
temp.SetPropertyNameOffset( _cbStringUsed / sizeof (WCHAR) );
|
||
|
|
||
|
Win4Assert( !iter.AtEnd() );
|
||
|
|
||
|
BYTE* pPropName;
|
||
|
ULONG cbName = iter.GetVariableRecSize();
|
||
|
|
||
|
if ( _cbStringUsed + cbName > _cbStrings )
|
||
|
GrowStringSpace( cbName );
|
||
|
|
||
|
iter.GetVariableRecData( (void*)&_pchStringBase[_cbStringUsed / sizeof (WCHAR)],
|
||
|
cbName );
|
||
|
|
||
|
_cbStringUsed += cbName;
|
||
|
|
||
|
ciDebugOut(( DEB_PIDTABLE,
|
||
|
"PIDTABLE: Named property\tpid = 0x%x, %ws\n",
|
||
|
temp.Pid(),
|
||
|
temp.GetPropertyNameOffset() + _pchStringBase ));
|
||
|
|
||
|
if (cbName == 0 || cbName > MAX_PROPERTY_NAME_LEN)
|
||
|
{
|
||
|
ciDebugOut(( DEB_WARN,
|
||
|
"PIDTABLE: Invalid named property\tpid = 0x%x, %ws\n",
|
||
|
temp.Pid(),
|
||
|
temp.GetPropertyNameOffset() + _pchStringBase ));
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ciDebugOut(( DEB_PIDTABLE,
|
||
|
"PIDTABLE: Numbered property\tpid = 0x%x, propid = %u\n",
|
||
|
temp.Pid(),
|
||
|
temp.GetPropertyPropid() ));
|
||
|
|
||
|
Win4Assert ( temp.IsPropertyPropid() );
|
||
|
if ( ! temp.IsPropertyPropid() )
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( temp.Pid() < INIT_DOWNLEVEL_PID )
|
||
|
{
|
||
|
ciDebugOut(( DEB_WARN,
|
||
|
"PIDTABLE: Invalid propid\tpid = 0x%x\n",
|
||
|
temp.Pid() ));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
StoreInTable(temp);
|
||
|
}
|
||
|
|
||
|
Win4Assert( Entries() == cEntriesFromFile );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
#endif // !defined(UNIT_TEST)
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CPidLookupTable::MakeBackupCopy
|
||
|
//
|
||
|
// Synopsis: Makes a backup copy of the persistent pid table.
|
||
|
//
|
||
|
// Arguments: [dstObj] - Destination object.
|
||
|
// [tracker] - Save progress tracker.
|
||
|
//
|
||
|
// History: 3-20-97 srikants Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CPidLookupTable::MakeBackupCopy( PRcovStorageObj & dstObj,
|
||
|
PSaveProgressTracker & tracker )
|
||
|
{
|
||
|
Win4Assert( !_xrsoPidTable.IsNull() );
|
||
|
CCopyRcovObject copier( dstObj, _xrsoPidTable.GetReference() );
|
||
|
copier.DoIt();
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::Hash, private
|
||
|
//
|
||
|
// Synopsis: Hash a CFullPropSpec value for use in a hash table.
|
||
|
//
|
||
|
// Arguments: [rProp] - a reference to the CFullPropSpec to be hashed
|
||
|
//
|
||
|
// Returns: ULONG - Hash value for the input CFullPropSpec
|
||
|
//
|
||
|
// Notes: The hash function xors only a few selected fields out
|
||
|
// of the GUID structure. It is intended to work well for
|
||
|
// both generated GUIDs (from UuidCreate) and administratively
|
||
|
// assigned GUIDs.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CPidLookupTable::Hash(
|
||
|
const CFullPropSpec & rProp )
|
||
|
{
|
||
|
const GUID & rGuid = rProp.GetPropSet();
|
||
|
|
||
|
ULONG ulHash = (rGuid.Data1 ^
|
||
|
(rGuid.Data4[0] << 16) ^
|
||
|
(rGuid.Data4[6] << 8) ^
|
||
|
(rGuid.Data4[7]));
|
||
|
|
||
|
if (rProp.IsPropertyPropid())
|
||
|
{
|
||
|
ulHash ^= (1 << 24) | rProp.GetPropertyPropid();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ulHash ^= HashString(rProp.GetPropertyName());
|
||
|
}
|
||
|
return ulHash;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::Hash, private
|
||
|
//
|
||
|
// Synopsis: Hash a CPidLookupEntry value (for rehashing)
|
||
|
//
|
||
|
// Arguments: [rProp] - a reference to the CPidLookupEntry to be hashed
|
||
|
//
|
||
|
// Returns: ULONG - Hash value for the input CPidLookupEntry
|
||
|
//
|
||
|
// Notes: The hash function xors only a few selected fields out
|
||
|
// of the GUID structure. It is intended to work well for
|
||
|
// both generated GUIDs (from UuidCreate) and administratively
|
||
|
// assigned GUIDs.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CPidLookupTable::Hash(
|
||
|
const CPidLookupEntry & rProp )
|
||
|
{
|
||
|
const GUID & rGuid = rProp.GetPropSet();
|
||
|
|
||
|
ULONG ulHash = (rGuid.Data1 ^
|
||
|
(rGuid.Data4[0] << 16) ^
|
||
|
(rGuid.Data4[6] << 8) ^
|
||
|
(rGuid.Data4[7]));
|
||
|
|
||
|
if (rProp.IsPropertyPropid())
|
||
|
{
|
||
|
ulHash ^= (1 << 24) | rProp.GetPropertyPropid();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const WCHAR * pwszStr = rProp.GetPropertyNameOffset() +
|
||
|
_pchStringBase;
|
||
|
|
||
|
ulHash ^= HashString(pwszStr);
|
||
|
}
|
||
|
return ulHash;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::HashString, private
|
||
|
//
|
||
|
// Synopsis: Hash a string from a property name.
|
||
|
//
|
||
|
// Arguments: [pwszStr] - the string to be hashed
|
||
|
//
|
||
|
// Returns: ULONG - Hash value for the input string
|
||
|
//
|
||
|
// Notes: Property names are assumed to be mapped to lower case.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CPidLookupTable::HashString( const WCHAR * pwszStr )
|
||
|
{
|
||
|
ULONG ulStrHash = 0;
|
||
|
|
||
|
while ( *pwszStr != L'\0' )
|
||
|
{
|
||
|
ulStrHash = (ulStrHash << 1) ^ (*pwszStr++);
|
||
|
}
|
||
|
|
||
|
return ulStrHash;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::LookUp, private
|
||
|
//
|
||
|
// Synopsis: Looks up a property in the hash table.
|
||
|
//
|
||
|
// Arguments: [Prop] - Property to look up.
|
||
|
// [riTable] - (output) Will contain the index in the hash
|
||
|
// table of the entry if found.
|
||
|
//
|
||
|
// Returns: TRUE if found; FALSE o/w
|
||
|
//
|
||
|
// History: 02 Jan 1996 Alanw Created
|
||
|
//
|
||
|
// Notes: On failure, riTable will point to an empty entry.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CPidLookupTable::LookUp( const CFullPropSpec & Prop, ULONG &riTable )
|
||
|
{
|
||
|
Win4Assert( 0 != Size() );
|
||
|
Win4Assert( !IsFull() );
|
||
|
|
||
|
ULONG iCur = Hash( Prop ) % Size();
|
||
|
ULONG iStart = iCur;
|
||
|
ULONG iDelta = iCur;
|
||
|
|
||
|
#if DBG==1
|
||
|
ULONG cSearchLen = 1;
|
||
|
#endif // DBG==1
|
||
|
|
||
|
BOOL fFound = FALSE;
|
||
|
while ( !fFound && ! _pTable[iCur].IsFree() )
|
||
|
{
|
||
|
|
||
|
if ( _pTable[iCur].IsEqual( Prop, _pchStringBase ) )
|
||
|
{
|
||
|
fFound = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
iCur = (iCur + iDelta) % Size();
|
||
|
if ( iCur == iStart ) // wrapped around
|
||
|
{
|
||
|
if ( 1 != iDelta )
|
||
|
{
|
||
|
iDelta = 1;
|
||
|
iCur = (iCur + 1) % Size();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Win4Assert( ! "Failed to find empty hash table entry" );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if DBG==1
|
||
|
cSearchLen++;
|
||
|
#endif // DBG==1
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if DBG==1
|
||
|
_cTotalSearches++;
|
||
|
_cTotalLength += cSearchLen;
|
||
|
if (cSearchLen > _cMaxChainLen)
|
||
|
_cMaxChainLen = cSearchLen;
|
||
|
#endif // DBG==1
|
||
|
|
||
|
riTable = iCur;
|
||
|
|
||
|
if (!fFound)
|
||
|
{
|
||
|
Win4Assert( _pTable[iCur].IsFree() );
|
||
|
}
|
||
|
return fFound;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::StoreInTable, private
|
||
|
//
|
||
|
// Synopsis: Stores a CPidLookupEntry in the hash table.
|
||
|
//
|
||
|
// Arguments: [Prop] - Property to store; must not be in the table
|
||
|
//
|
||
|
// Returns: NOTHING
|
||
|
//
|
||
|
// History: 02 Jan 1996 Alanw Created
|
||
|
//
|
||
|
// Notes: This function is used in rehashing and the initial load of
|
||
|
// the table. It is not expected to find the property, but it
|
||
|
// returns the slot in which the entry should be placed.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CPidLookupTable::StoreInTable( const CPidLookupEntry & Prop )
|
||
|
{
|
||
|
Win4Assert( 0 != Size() );
|
||
|
Win4Assert( !IsFull() );
|
||
|
|
||
|
ULONG iCur = Hash( Prop ) % Size();
|
||
|
ULONG iStart = iCur;
|
||
|
ULONG iDelta = iCur;
|
||
|
|
||
|
#if DBG==1
|
||
|
ULONG cSearchLen = 1;
|
||
|
#endif // DBG==1
|
||
|
|
||
|
while ( ! _pTable[iCur].IsFree() )
|
||
|
{
|
||
|
|
||
|
#if DBG==1
|
||
|
if (Prop.IsPropertyPropid())
|
||
|
{
|
||
|
Win4Assert( !_pTable[iCur].IsPropertyPropid() ||
|
||
|
Prop.GetPropertyPropid() != _pTable[iCur].GetPropertyPropid() ||
|
||
|
Prop.GetPropSet() != _pTable[iCur].GetPropSet());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Win4Assert( !_pTable[iCur].IsPropertyName() ||
|
||
|
Prop.GetPropSet() != _pTable[iCur].GetPropSet() ||
|
||
|
_wcsicmp( Prop.GetPropertyNameOffset() +
|
||
|
_pchStringBase,
|
||
|
_pTable[iCur].GetPropertyNameOffset() +
|
||
|
_pchStringBase) != 0);
|
||
|
}
|
||
|
#endif // DBG==1
|
||
|
|
||
|
iCur = (iCur + iDelta) % Size();
|
||
|
if ( iCur == iStart ) // wrapped around
|
||
|
{
|
||
|
if ( 1 != iDelta )
|
||
|
{
|
||
|
iDelta = 1;
|
||
|
iCur = (iCur + 1) % Size();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Win4Assert( ! "Failed to find empty hash table entry" );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if DBG==1
|
||
|
cSearchLen++;
|
||
|
#endif // DBG==1
|
||
|
|
||
|
}
|
||
|
|
||
|
#if DBG==1
|
||
|
if (cSearchLen > _cMaxChainLen)
|
||
|
_cMaxChainLen = cSearchLen;
|
||
|
#endif // DBG==1
|
||
|
|
||
|
_pTable[iCur] = Prop;
|
||
|
_Header.cEntries++;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::GrowSize, private
|
||
|
//
|
||
|
// Synopsis: For a given valid hash table entries, this routine figures
|
||
|
// out the next valid size (close approximation to a prime).
|
||
|
//
|
||
|
// Arguments: - NONE -
|
||
|
//
|
||
|
// Returns: The size of the hash table for the given number of valid
|
||
|
// entries.
|
||
|
//
|
||
|
// History: 1-09-95 srikants Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CPidLookupTable::GrowSize ( void ) const
|
||
|
{
|
||
|
ULONG size = Size() + 2;
|
||
|
|
||
|
for (unsigned i = 0; i < g_cPrimes && g_aPrimes[i] < size; i++)
|
||
|
;
|
||
|
|
||
|
if (i < g_cPrimes)
|
||
|
return g_aPrimes[i];
|
||
|
|
||
|
// make it power of two - 1
|
||
|
// a good approximation of a prime
|
||
|
|
||
|
for ( unsigned sizeInit = 1; sizeInit < size; sizeInit *= 2 )
|
||
|
continue;
|
||
|
|
||
|
return (sizeInit - 1);
|
||
|
} //GrowSize
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::AddEntry, private
|
||
|
//
|
||
|
// Synopsis: Adds a property entry in the hash table.
|
||
|
//
|
||
|
// Arguments: [Prop] - Property to Add
|
||
|
//
|
||
|
// Returns: ULONG - the index of the entry used to store the property
|
||
|
//
|
||
|
// History: 02 Jan 1996 Alanw Created
|
||
|
//
|
||
|
// Notes: It is assumed that the entry does not already exist in the
|
||
|
// table. The input property spec has already been normalized
|
||
|
// and checked for error.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CPidLookupTable::AddEntry( const CFullPropSpec & Prop )
|
||
|
{
|
||
|
if (Size() == 0 ||
|
||
|
Entries() >= _maxEntries)
|
||
|
{
|
||
|
GrowAndRehash( GrowSize() );
|
||
|
}
|
||
|
|
||
|
ULONG cbNameLength = 0;
|
||
|
|
||
|
if (Prop.IsPropertyName())
|
||
|
{
|
||
|
cbNameLength = ( wcslen(Prop.GetPropertyName()) + 1) * sizeof (WCHAR);
|
||
|
|
||
|
//
|
||
|
// Check for a bogus null property name
|
||
|
//
|
||
|
Win4Assert( cbNameLength > sizeof (WCHAR) );
|
||
|
Win4Assert( cbNameLength <= MAX_PROPERTY_NAME_LEN );
|
||
|
|
||
|
if (_cbStringUsed + cbNameLength > _cbStrings)
|
||
|
{
|
||
|
GrowStringSpace( cbNameLength );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ULONG iEntry = ~0u;
|
||
|
BOOL fFound = LookUp( Prop, iEntry );
|
||
|
|
||
|
Win4Assert( fFound == FALSE && iEntry < Size() &&
|
||
|
_pTable[iEntry].IsFree() );
|
||
|
|
||
|
_pTable[iEntry].SetPropSet( Prop.GetPropSet() );
|
||
|
if ( Prop.IsPropertyPropid() )
|
||
|
{
|
||
|
_pTable[iEntry].SetPropertyPropid( Prop.GetPropertyPropid() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WCHAR * pchName = _pchStringBase + (_cbStringUsed / sizeof (WCHAR));
|
||
|
RtlCopyMemory( pchName, Prop.GetPropertyName(), cbNameLength );
|
||
|
_cbStringUsed += cbNameLength;
|
||
|
_pTable[iEntry].SetPropertyNameOffset( (ULONG)(pchName - _pchStringBase) );
|
||
|
|
||
|
Win4Assert( _cbStringUsed <= _cbStrings );
|
||
|
}
|
||
|
_pTable[iEntry].SetPid( NextPropid() );
|
||
|
|
||
|
_Header.NextPropid++;
|
||
|
_Header.cEntries++;
|
||
|
|
||
|
#if !defined(UNIT_TEST)
|
||
|
//
|
||
|
// Write new mapping to the recoverable storage
|
||
|
//
|
||
|
|
||
|
CRcovStorageHdr & hdr = _xrsoPidTable->GetHeader();
|
||
|
CRcovStrmAppendTrans xact( _xrsoPidTable.GetReference() );
|
||
|
CRcovStrmAppendIter iter( xact, sizeof (CPidLookupEntry) );
|
||
|
|
||
|
iter.AppendRec( &_pTable[iEntry] );
|
||
|
|
||
|
ULONG cRecordsWritten = 1;
|
||
|
|
||
|
if (cbNameLength)
|
||
|
{
|
||
|
iter.AppendVariableRec( Prop.GetPropertyName(), cbNameLength );
|
||
|
cRecordsWritten++;
|
||
|
|
||
|
}
|
||
|
|
||
|
struct CRcovUserHdr data;
|
||
|
RtlCopyMemory( &data._abHdr, &_Header, sizeof(_Header) );
|
||
|
|
||
|
Win4Assert( hdr.GetCount(hdr.GetBackup()) == hdr.GetCount(hdr.GetPrimary()) + cRecordsWritten);
|
||
|
hdr.SetUserHdr( hdr.GetBackup(), data );
|
||
|
xact.Commit();
|
||
|
#endif // !defined(UNIT_TEST)
|
||
|
|
||
|
return iEntry;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::GrowAndRehash, private
|
||
|
//
|
||
|
// Synopsis: Grow the hash table in a CPidLookupTable
|
||
|
//
|
||
|
// Arguments: [cNewHash] - number of hash buckets to allocate
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CPidLookupTable::GrowAndRehash( ULONG cNewHash )
|
||
|
{
|
||
|
Win4Assert( cNewHash > Size() );
|
||
|
|
||
|
ULONG cOldSize = Size();
|
||
|
ULONG cOldEntries = Entries();
|
||
|
|
||
|
XPtr<CPidLookupEntry> pOldTable( _pTable );
|
||
|
_pTable = 0;
|
||
|
|
||
|
Init( cNewHash );
|
||
|
|
||
|
for (unsigned i = 0; i < cOldSize; i++)
|
||
|
{
|
||
|
if ((pOldTable.GetPointer() + i)->IsFree())
|
||
|
continue;
|
||
|
|
||
|
StoreInTable( *(pOldTable.GetPointer() + i) );
|
||
|
}
|
||
|
|
||
|
Win4Assert( Entries() < Size() && Entries() < _maxEntries );
|
||
|
Win4Assert( Entries() == cOldEntries );
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::GrowStringSpace, private
|
||
|
//
|
||
|
// Synopsis: Grow the string space in a CPidLookupTable
|
||
|
//
|
||
|
// Arguments: [cbNewString] - size (in bytes) to reserve for new string
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CPidLookupTable::GrowStringSpace( ULONG cbNewString )
|
||
|
{
|
||
|
ULONG cbNew = _cbStringUsed + 2*cbNewString;
|
||
|
Win4Assert( cbNew > _cbStrings );
|
||
|
|
||
|
WCHAR * pchNew = new WCHAR[ cbNew/sizeof (WCHAR) ];
|
||
|
|
||
|
if ( 0 != _cbStringUsed )
|
||
|
{
|
||
|
RtlCopyMemory( pchNew, _pchStringBase, _cbStringUsed );
|
||
|
delete [] _pchStringBase;
|
||
|
}
|
||
|
_pchStringBase = pchNew;
|
||
|
_cbStrings = cbNew;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::FindPropid, public
|
||
|
//
|
||
|
// Synopsis: Looks up a property entry in the hash table.
|
||
|
//
|
||
|
// Arguments: [Prop] - Property to lookup
|
||
|
// [rPid] - Propid found
|
||
|
// [fAddToTable] - If TRUE, add Prop to table if it was not
|
||
|
// found.
|
||
|
//
|
||
|
// Returns: BOOL - TRUE if Prop was found or successfully added.
|
||
|
//
|
||
|
// History: 02 Jan 1996 Alanw Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CPidLookupTable::FindPropid( const CFullPropSpec & InputProp,
|
||
|
PROPID & rPid,
|
||
|
BOOL fAddToTable )
|
||
|
{
|
||
|
rPid = pidInvalid;
|
||
|
|
||
|
ULONG cbNameLength = 0;
|
||
|
CFullPropSpec Prop;
|
||
|
|
||
|
if (InputProp.IsPropertyPropid())
|
||
|
{
|
||
|
Win4Assert( InputProp.GetPropertyPropid() != PID_DICTIONARY &&
|
||
|
InputProp.GetPropertyPropid() != PID_CODEPAGE );
|
||
|
if (InputProp.GetPropertyPropid() <= PID_CODEPAGE )
|
||
|
return FALSE;
|
||
|
|
||
|
Prop = InputProp;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// map the input property name to lower case
|
||
|
Win4Assert( InputProp.IsPropertyName() );
|
||
|
|
||
|
if ( InputProp.GetPropertyName() == 0 ||
|
||
|
*InputProp.GetPropertyName() == L'\0' )
|
||
|
{
|
||
|
Win4Assert( !"CPidLookupTable - bad named property!" );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
CLowcaseBuf wcsBuf( InputProp.GetPropertyName() );
|
||
|
|
||
|
cbNameLength = (wcsBuf.Length() + 1) * sizeof (WCHAR);
|
||
|
|
||
|
if ( cbNameLength >= MAX_PROPERTY_NAME_LEN )
|
||
|
{
|
||
|
ciDebugOut(( DEB_WARN,
|
||
|
"PIDTABLE: long named property truncated\t%ws\n",
|
||
|
InputProp.GetPropertyName() ));
|
||
|
|
||
|
// Truncate the property name if it's too long.
|
||
|
cbNameLength = MAX_PROPERTY_NAME_LEN;
|
||
|
(wcsBuf.GetWriteable())[(cbNameLength/sizeof(WCHAR))-1] = L'\0';
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// It would be nice if we could just use the lower-cased string
|
||
|
// from the CLowcaseBuf directly, but it's about to go out of scope.
|
||
|
//
|
||
|
Prop.SetPropSet( InputProp.GetPropSet() );
|
||
|
Prop.SetProperty( wcsBuf.Get( ) );
|
||
|
|
||
|
if ( !Prop.IsValid() )
|
||
|
THROW( CException( E_OUTOFMEMORY ) );
|
||
|
}
|
||
|
|
||
|
if ( !Prop.IsValid() )
|
||
|
return FALSE;
|
||
|
|
||
|
CLock lock ( _mutex );
|
||
|
|
||
|
ULONG iEntry = ~0u;
|
||
|
BOOL fFound = LookUp( Prop, iEntry );
|
||
|
|
||
|
if ( ! fFound && fAddToTable )
|
||
|
{
|
||
|
CImpersonateSystem impersonate;
|
||
|
|
||
|
iEntry = AddEntry( Prop );
|
||
|
fFound = TRUE;
|
||
|
}
|
||
|
|
||
|
if (fFound)
|
||
|
{
|
||
|
rPid = _pTable[iEntry].Pid();
|
||
|
Win4Assert( iEntry < Size() && ! _pTable[iEntry].IsFree() );
|
||
|
}
|
||
|
|
||
|
return fFound;
|
||
|
} //FindPropid
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CPidLookupTable::EnumerateProperty, public
|
||
|
//
|
||
|
// Synopsis: Enumerate properties in the property list
|
||
|
//
|
||
|
// Arguments: [ps] -- Full PropSpec returned here
|
||
|
// [iBmk] -- Bookmark. Initialized to 0 before first call.
|
||
|
//
|
||
|
// Returns: BOOL equivalent: PROPID, 0 if at the end of the enumeration.
|
||
|
//
|
||
|
// History: 20-Jun-1996 KyleP Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CPidLookupTable::EnumerateProperty( CFullPropSpec & ps, unsigned & iBmk )
|
||
|
{
|
||
|
for ( ; iBmk < Size() && _pTable[iBmk].IsFree(); iBmk++ )
|
||
|
continue;
|
||
|
|
||
|
PROPID pid = 0;
|
||
|
|
||
|
if ( iBmk >= Size() )
|
||
|
return 0;
|
||
|
|
||
|
ps.SetPropSet( _pTable[iBmk].GetPropSet() );
|
||
|
|
||
|
if ( _pTable[iBmk].IsPropertyPropid() )
|
||
|
ps.SetProperty( _pTable[iBmk].GetPropertyPropid() );
|
||
|
else
|
||
|
{
|
||
|
ps.SetProperty( _pTable[iBmk].GetPropertyNameOffset() + _pchStringBase );
|
||
|
if ( !ps.IsValid() )
|
||
|
THROW( CException( E_OUTOFMEMORY ) );
|
||
|
}
|
||
|
|
||
|
pid = _pTable[iBmk].Pid();
|
||
|
|
||
|
iBmk++;
|
||
|
return pid;
|
||
|
} //EnumerateProperty
|
||
|
|