523 lines
17 KiB
C
523 lines
17 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1998 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
cmmprops.h
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains the definition of the property search class
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Keith Lau (keithlau@microsoft.com)
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
keithlau 03/02/98 created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#ifndef _PROPS_H_
|
||
|
#define _PROPS_H_
|
||
|
|
||
|
#include "blockmgr.h"
|
||
|
#include "propid.h"
|
||
|
#include "mailmsgprops.h"
|
||
|
|
||
|
/*
|
||
|
|
||
|
This file defines a generice class for property tables. The following is
|
||
|
the terminology used in relation to property tables:
|
||
|
|
||
|
Search key - A value used to uniquely identify a property
|
||
|
Property - A tuple consisting of a { Property Identifier, Value } pair.
|
||
|
Property Identifier - the search key for the property table. The property
|
||
|
table class does not restrict the data type or length of the property
|
||
|
identifier, but rather, the caller must specify the length of the
|
||
|
property identifier and provide a compare function when an instance
|
||
|
of the property table is created.
|
||
|
Value - A tuple consisting of a { Offset, Length } pair. The offset points
|
||
|
to the physical location of the value and its length is specified by
|
||
|
the Length element.
|
||
|
Property Table - A collection of properties keyed off the designated
|
||
|
property identifier.
|
||
|
|
||
|
A property table contains an instance info record (PROPERTY_TABLE_INSTANCE),
|
||
|
which describes the parameters of the table, such as the length of each
|
||
|
property item record (PROPERTY_ITEM), how many items fit in a fragment
|
||
|
(PROPERTY_TABLE_FRAGMENT), and a link to the first fragment.
|
||
|
|
||
|
Fragments are linked together and thus a property table can hold an
|
||
|
arbitrarily larger number of properties, until the identifier space is
|
||
|
exhausted. Fragments contain property item records, each item record
|
||
|
contains an ordered tuple: { Offset, Length, Max Length, Property Identifier }
|
||
|
In the definition of PROPERTY_ITEM, the Property Identifier element is not
|
||
|
explicitly defined, but it is implied that whatever follows Max Length
|
||
|
is the property identifier. This allows maximum flexibility for different
|
||
|
search key types. Similarly, although PROPERTY_TABLE_FRAGMENT does not
|
||
|
include an array of PROPERTY_ITEMs, it is implied that an array of item
|
||
|
records follow after faNextFragment. The size of the property identifier field
|
||
|
is specified during instance creation so the size of each property item
|
||
|
is fixed and known at run time.
|
||
|
|
||
|
Since the property identifiers can be of different sizes, the creator must
|
||
|
provide a function that knows how to compare a search key against a
|
||
|
property item.
|
||
|
|
||
|
A memory manager must be specified when the property table is created.
|
||
|
This provides a mechanism for memory to be allocated and released in
|
||
|
a linear, flat address space.
|
||
|
*/
|
||
|
|
||
|
// Define the well-known property item structure. We will have a sorted
|
||
|
// array of these items that make up the list of well-known properties.
|
||
|
//
|
||
|
// Arrays of this type MUST be sorted for correct search results.
|
||
|
typedef struct _INTERNAL_PROPERTY_ITEM
|
||
|
{
|
||
|
PROP_ID idProp; // Prop ID
|
||
|
DWORD dwIndex; // Reserved index of this prop ID
|
||
|
|
||
|
} INTERNAL_PROPERTY_ITEM, *LPINTERNAL_PROPERTY_ITEM;
|
||
|
|
||
|
// Define a generic structure to represent a property in the property
|
||
|
// table
|
||
|
// Each property table that uses this class as the accessor must have
|
||
|
// an item structure that includes this structure as its first member
|
||
|
typedef struct _PROPERTY_ITEM
|
||
|
{
|
||
|
FLAT_ADDRESS faOffset; // Offset in flat space to value
|
||
|
DWORD dwSize; // Size of value data in bytes
|
||
|
DWORD dwMaxSize; // Max size allocated for value
|
||
|
|
||
|
} PROPERTY_ITEM, *LPPROPERTY_ITEM;
|
||
|
|
||
|
// Define a generic structure to describe a fragment in the property table
|
||
|
typedef struct _PROPERTY_TABLE_FRAGMENT
|
||
|
{
|
||
|
DWORD dwSignature; // Signature of fragment
|
||
|
FLAT_ADDRESS faNextFragment; // Link to next fragment
|
||
|
|
||
|
} PROPERTY_TABLE_FRAGMENT, *LPPROPERTY_TABLE_FRAGMENT;
|
||
|
|
||
|
// Define a function type specifying the generic compare function passed
|
||
|
// into the search routine
|
||
|
//
|
||
|
// Arguments:
|
||
|
// LPVOID - pointer to search key value, the compare function must have
|
||
|
// intimate knowledge of how to retrieve the property key from
|
||
|
// the pointer and its size.
|
||
|
// LPPROPERTY_ITEM - pointer to item to compare against. The compare
|
||
|
// function must have intimate knowledge of how to retrieve the
|
||
|
// property key from the item pointer. The actual size of this
|
||
|
// structure is in PROPERTY_TABLE_INSTANCE.dwItemSize.
|
||
|
//
|
||
|
// Return values:
|
||
|
// SUCCESS(HRESULT) - The item matches the search key
|
||
|
// !SUCCESS(HRESULT) - The item does not match the search key
|
||
|
//
|
||
|
typedef HRESULT (*LPPROPERTY_COMPARE_FUNCTION)(LPVOID, LPPROPERTY_ITEM);
|
||
|
|
||
|
// Define a generic structure to describe the property table instance
|
||
|
// Each property table that uses this class as the accessor must have
|
||
|
// an instance structure that includes this structure as its first member
|
||
|
typedef struct _PROPERTY_TABLE_INSTANCE
|
||
|
{
|
||
|
DWORD dwSignature; // Signature of instance
|
||
|
FLAT_ADDRESS faFirstFragment;// Link to first fragment
|
||
|
DWORD dwFragmentSize; // Size of each fragment
|
||
|
DWORD dwItemBits; // # lower bits that represent the item
|
||
|
DWORD dwItemSize; // Size of a specific PROPERTY_ITEM
|
||
|
DWORD dwProperties; // # properties in this instance
|
||
|
FLAT_ADDRESS faExtendedInfo; // Link to any specific extended into
|
||
|
|
||
|
} PROPERTY_TABLE_INSTANCE, *LPPROPERTY_TABLE_INSTANCE;
|
||
|
|
||
|
// Enumerate the different applications of the property table
|
||
|
// This is used to track what kind of table we are looking at for debugging
|
||
|
typedef enum _PROPERTY_TABLE_TYPES
|
||
|
{
|
||
|
PTT_INVALID_TYPE = 0, // Default value
|
||
|
PTT_PROPERTY_TABLE, // Standard property table
|
||
|
PTT_RECIPIENT_TABLE, // Recipient table
|
||
|
PTT_PROP_ID_TABLE // Prop ID management table
|
||
|
|
||
|
} PROPERTY_TABLE_TYPES;
|
||
|
|
||
|
// Enumerate the different types of operations GetOrSetNextExistingItem
|
||
|
// supports
|
||
|
typedef enum _PROPERTY_ITEM_OPERATIONS
|
||
|
{
|
||
|
PIO_INVALID_TYPE = 0, // Default value
|
||
|
PIO_READ_ITEM, // Normal read
|
||
|
PIO_WRITE_ITEM, // Normal write
|
||
|
PIO_ATOMIC_WRITE_ITEM // Protected write
|
||
|
|
||
|
} PROPERTY_ITEM_OPERATIONS;
|
||
|
|
||
|
#include "cmmtypes.h"
|
||
|
|
||
|
// =================================================================
|
||
|
// class for accessing items from the property table. This class
|
||
|
// hides the details of fragmentation.
|
||
|
//
|
||
|
// This class is single-threaded
|
||
|
//
|
||
|
class CPropertyTableItem
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
CPropertyTableItem(
|
||
|
CBlockManager *pBlockManager,
|
||
|
LPPROPERTY_TABLE_INSTANCE pInstanceInfo
|
||
|
);
|
||
|
~CPropertyTableItem();
|
||
|
|
||
|
HRESULT AddItem(
|
||
|
LPPROPERTY_ITEM pItem,
|
||
|
DWORD *pdwIndex,
|
||
|
FLAT_ADDRESS *pfaOffsetToItem = NULL
|
||
|
);
|
||
|
|
||
|
HRESULT UpdateItem(
|
||
|
DWORD dwIndex,
|
||
|
LPPROPERTY_ITEM pItem,
|
||
|
FLAT_ADDRESS *pfaOffsetToItem = NULL
|
||
|
);
|
||
|
|
||
|
HRESULT GetItemAtIndex(
|
||
|
DWORD dwIndex,
|
||
|
LPPROPERTY_ITEM pItem,
|
||
|
LPFLAT_ADDRESS pfaOffset = NULL
|
||
|
);
|
||
|
|
||
|
HRESULT GetNextItem(
|
||
|
LPPROPERTY_ITEM pItem
|
||
|
);
|
||
|
|
||
|
HRESULT GetOffsetToCurrentItem(
|
||
|
FLAT_ADDRESS *pfaOffset
|
||
|
)
|
||
|
{ if (pfaOffset) *pfaOffset = m_faOffsetToCurrentItem; return(S_OK); }
|
||
|
|
||
|
private:
|
||
|
|
||
|
HRESULT GetOrSetNextExistingItem(
|
||
|
// This looks at m_dwCurrentItem for index
|
||
|
LPPROPERTY_ITEM pItem,
|
||
|
DWORD dwOperation,
|
||
|
LPFLAT_ADDRESS pfaOffset = NULL
|
||
|
);
|
||
|
|
||
|
HRESULT ReadFragmentFromFragmentNumber(
|
||
|
DWORD dwFragmentNumber
|
||
|
);
|
||
|
|
||
|
HRESULT ReadFragment(
|
||
|
FLAT_ADDRESS faOffset
|
||
|
);
|
||
|
|
||
|
public:
|
||
|
HRESULT ReadItem(
|
||
|
FLAT_ADDRESS faOffset,
|
||
|
LPPROPERTY_ITEM pItem
|
||
|
);
|
||
|
|
||
|
private:
|
||
|
HRESULT WriteItem(
|
||
|
FLAT_ADDRESS faOffset,
|
||
|
LPPROPERTY_ITEM pItem,
|
||
|
BOOL fAtomic
|
||
|
);
|
||
|
|
||
|
// Info of parent instance
|
||
|
LPPROPERTY_TABLE_INSTANCE m_pInstanceInfo;
|
||
|
|
||
|
// Current fragment being processed
|
||
|
BOOL m_fLoaded;
|
||
|
PROPERTY_TABLE_FRAGMENT m_Fragment;
|
||
|
DWORD m_dwCurrentFragment;
|
||
|
FLAT_ADDRESS m_faOffsetToFragment;
|
||
|
DWORD m_dwCurrentItem;
|
||
|
DWORD m_dwCurrentItemInFragment;
|
||
|
FLAT_ADDRESS m_faOffsetToCurrentItem;
|
||
|
|
||
|
// Memory manager pointer and context for fast access
|
||
|
CBlockManager *m_pBlockManager;
|
||
|
CBlockContext m_bcContext;
|
||
|
};
|
||
|
|
||
|
// =================================================================
|
||
|
// class for accessing an instance of a property table
|
||
|
//
|
||
|
class CPropertyTable
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
CPropertyTable(
|
||
|
PROPERTY_TABLE_TYPES pttTableType,
|
||
|
DWORD dwValidSignature,
|
||
|
CBlockManager *pBlockManager,
|
||
|
LPPROPERTY_TABLE_INSTANCE pInstanceInfo,
|
||
|
LPPROPERTY_COMPARE_FUNCTION pfnCompare,
|
||
|
const LPINTERNAL_PROPERTY_ITEM pInternalProperties = NULL,
|
||
|
DWORD dwInternalProperties = 0
|
||
|
);
|
||
|
~CPropertyTable();
|
||
|
|
||
|
BOOL IsValid();
|
||
|
BOOL IsInstanceInfoValid();
|
||
|
|
||
|
//
|
||
|
// Method to return the property count
|
||
|
//
|
||
|
// GetCount - Returns the current property count
|
||
|
//
|
||
|
// Arguments
|
||
|
// pdwCount - Pointer to DWORD to return count
|
||
|
//
|
||
|
// Return values
|
||
|
//
|
||
|
// S_OK - Succeeded
|
||
|
//
|
||
|
HRESULT GetCount(
|
||
|
DWORD *pdwCount
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Method to create or update a property item and value given a search key
|
||
|
//
|
||
|
// PutProperty - Creates the specified property if the property does not
|
||
|
// exist, or updates the value of the property otherwise.
|
||
|
//
|
||
|
// Arguments
|
||
|
// pvPropKey - Pointer to the search key
|
||
|
// pItem - Pointer to the property item to write
|
||
|
// dwSize - Size of property value data
|
||
|
// pbValue - Pointer to property value data. If this value is NULL,
|
||
|
// then no data is written, only the item record is created
|
||
|
// or updated. dwSize must also be zero.
|
||
|
//
|
||
|
// Return values
|
||
|
//
|
||
|
// S_OK - Succeeded, property already exists, but the
|
||
|
// value is updated as specified.
|
||
|
// S_FALSE - Succeeded, new property is created
|
||
|
// STG_E_INVALIDPARAMETER - Error, one or more parameters are invalid, or
|
||
|
// otherwise inconsistent.
|
||
|
// STG_E_WRITEFAULT - Error, The write failed to complete.
|
||
|
// TYPE_E_OUTOFBOUNDS - Debug Error, a write is issued to write past
|
||
|
// the current allocated block.
|
||
|
//
|
||
|
HRESULT PutProperty(
|
||
|
LPVOID pvPropKey,
|
||
|
LPPROPERTY_ITEM pItem,
|
||
|
DWORD dwSize,
|
||
|
LPBYTE pbValue
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Method to retrieve a property item given a search key
|
||
|
//
|
||
|
// GetPropertyItem - Attempts to find the property item specified by the
|
||
|
// Search key. If found, the property item record will
|
||
|
// be returned.
|
||
|
//
|
||
|
// Arguments
|
||
|
// pvPropKey - Pointer to the search key
|
||
|
// pItem - Pointer to the property item to return, sufficient space
|
||
|
// must be allocated by the caller to hold the property item
|
||
|
//
|
||
|
// Return values
|
||
|
//
|
||
|
// S_OK - Succeeded
|
||
|
// STG_E_UNKNOWN - Error, specified property not found.
|
||
|
// STG_E_INVALIDPARAMETER - Error, one or more parameters are invalid, or
|
||
|
// otherwise inconsistent.
|
||
|
// STG_E_READFAULT - Error, The read failed to complete.
|
||
|
// TYPE_E_OUTOFBOUNDS - Debug Error, a read is issued to write past
|
||
|
// the current allocated block.
|
||
|
//
|
||
|
HRESULT GetPropertyItem(
|
||
|
LPVOID pvPropKey,
|
||
|
LPPROPERTY_ITEM pItem
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Method to retrieve a property item and its associated value
|
||
|
//
|
||
|
// GetPropertyItemAndValue - Attempts to find the property item specified
|
||
|
// by the Search key. If found, the property item record, as
|
||
|
// well as the value data will be returned.
|
||
|
//
|
||
|
// Arguments
|
||
|
// pvPropKey - Pointer to the search key
|
||
|
// pItem - Pointer to the property item to return, sufficient space
|
||
|
// must be allocated by the caller to hold the property item
|
||
|
// dwLength - Size of buffer allocated for value data
|
||
|
// pdwLengthRead- Size of value data actually read, if the provided buffer is
|
||
|
// insufficient, then the full length of the property data is
|
||
|
// returned.
|
||
|
// pbValue - Pointer to return property value data.
|
||
|
//
|
||
|
// Return values
|
||
|
//
|
||
|
// S_OK - Succeeded
|
||
|
// STG_E_UNKNOWN - Error, specified property not found.
|
||
|
// HRESULT_FROM_WIN32(ERROR_MORE_DATA) - Error, the buffer provided is not
|
||
|
// large enough to hold all the value data.
|
||
|
// *pdwLengthRead returns the full length. *pItem
|
||
|
// would still return the item record in this case.
|
||
|
// STG_E_INVALIDPARAMETER - Error, one or more parameters are invalid, or
|
||
|
// otherwise inconsistent.
|
||
|
// STG_E_READFAULT - Error, The read failed to complete.
|
||
|
// TYPE_E_OUTOFBOUNDS - Debug Error, a read is issued to write past
|
||
|
// the current allocated block.
|
||
|
//
|
||
|
HRESULT GetPropertyItemAndValue(
|
||
|
LPVOID pvPropKey,
|
||
|
LPPROPERTY_ITEM pItem,
|
||
|
DWORD dwLength,
|
||
|
DWORD *pdwLengthRead,
|
||
|
LPBYTE pbValue
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Method to retrieve a property item and its associated value, using an
|
||
|
// internal index instead of a search key.
|
||
|
//
|
||
|
// GetPropertyItemAndValueUsingIndex - Attempts to find the property item
|
||
|
// specified by the Search key. If found, the property item
|
||
|
// record, as well as the value data will be returned.
|
||
|
//
|
||
|
// Arguments
|
||
|
// dwIndex - Index of item to retrieve, this is actually the dwIndex'th
|
||
|
// item in the property table. One can walk the entire table
|
||
|
// using this method.
|
||
|
// pItem - Pointer to the property item to return, sufficient space
|
||
|
// must be allocated by the caller to hold the property item
|
||
|
// dwLength - Size of buffer allocated for value data
|
||
|
// pdwLengthRead- Size of value data actually read, if the provided buffer is
|
||
|
// insufficient, then the full length of the property data is
|
||
|
// returned.
|
||
|
// pbValue - Pointer to return property value data.
|
||
|
//
|
||
|
// Return values
|
||
|
//
|
||
|
// S_OK - Succeeded
|
||
|
// STG_E_UNKNOWN - Error, specified property not found.
|
||
|
// HRESULT_FROM_WIN32(ERROR_MORE_DATA) - Error, the buffer provided is not
|
||
|
// large enough to hold all the value data.
|
||
|
// *pdwLengthRead returns the full length. *pItem
|
||
|
// would still return the item record in this case.
|
||
|
// STG_E_INVALIDPARAMETER - Error, one or more parameters are invalid, or
|
||
|
// otherwise inconsistent.
|
||
|
// STG_E_READFAULT - Error, The read failed to complete.
|
||
|
// TYPE_E_OUTOFBOUNDS - Debug Error, a read is issued to write past
|
||
|
// the current allocated block.
|
||
|
//
|
||
|
HRESULT GetPropertyItemAndValueUsingIndex(
|
||
|
DWORD dwIndex,
|
||
|
LPPROPERTY_ITEM pItem,
|
||
|
DWORD dwLength,
|
||
|
DWORD *pdwLengthRead,
|
||
|
LPBYTE pbValue
|
||
|
);
|
||
|
|
||
|
private:
|
||
|
|
||
|
// Method to search the property table and return the associated
|
||
|
// property item, if found
|
||
|
HRESULT SearchForProperty(
|
||
|
LPVOID pvPropKey,
|
||
|
LPPROPERTY_ITEM pItem,
|
||
|
DWORD *pdwIndexToItem,
|
||
|
FLAT_ADDRESS *pfaOffsetToItem
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// map a propid into an array index into m_rgWellKnownProps. returns
|
||
|
// -1 if the prop isn't well known
|
||
|
//
|
||
|
int MapCachedProp(DWORD iPropId) {
|
||
|
if (m_cCachedProps &&
|
||
|
iPropId >= m_iCachedPropsBase &&
|
||
|
iPropId < m_iCachedPropsBase + m_cCachedProps)
|
||
|
{
|
||
|
int i = iPropId - m_iCachedPropsBase;
|
||
|
_ASSERT(i < (int) m_cCachedProps);
|
||
|
return i;
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize the property cache
|
||
|
//
|
||
|
void InitializePropCache();
|
||
|
|
||
|
//
|
||
|
// set an item in the property cache. to invalidate an item pass in
|
||
|
// INVALID_FLAT_ADDRESS for fa.
|
||
|
//
|
||
|
void UpdatePropCache(LPPROPERTY_ITEM pItem,
|
||
|
FLAT_ADDRESS fa,
|
||
|
DWORD dwIndex);
|
||
|
|
||
|
DWORD m_dwSignature;
|
||
|
DWORD m_dwTableType;
|
||
|
DWORD m_dwValidInstanceSignature;
|
||
|
|
||
|
// Keep a local instance structure, and track the offset to the
|
||
|
// copy in flat space
|
||
|
PROPERTY_TABLE_INSTANCE *m_pInstanceInfo;
|
||
|
|
||
|
// List of well-known properties, we will use the count to determine
|
||
|
// whether there are any well-known properties
|
||
|
//
|
||
|
// Note that well-known
|
||
|
LPINTERNAL_PROPERTY_ITEM m_pInternalProperties;
|
||
|
DWORD m_dwInternalProperties;
|
||
|
|
||
|
// Function pointer to do property comparisons
|
||
|
LPPROPERTY_COMPARE_FUNCTION m_pfnCompare;
|
||
|
|
||
|
// Memory manager to use
|
||
|
CBlockManager *m_pBlockManager;
|
||
|
|
||
|
// this structure is used for each item in the cache.
|
||
|
typedef struct {
|
||
|
// the flat address for this item, or INVALID_FLAT_ADDRESS if its not in the cache
|
||
|
FLAT_ADDRESS fa;
|
||
|
// its index
|
||
|
DWORD dwIndex;
|
||
|
} PROPCACHEITEM;
|
||
|
|
||
|
// array of cached property offsets for the predefined properties.
|
||
|
// if its GLOBAL_PTABLE_INSTANCE_SIGNATURE_VALID
|
||
|
// then this has the prop ids from IMMPID_MP_BEFORE+1 to IMMPID_MP_AFTER
|
||
|
// otherwise this will be NULL
|
||
|
//
|
||
|
// There is no reason to cache recipient property offsets at this
|
||
|
// time since the recipient property table is instantiated, used
|
||
|
// once, then thrown away. we'd spend more time making the cache
|
||
|
// then the linear search in SearchForProperty costs
|
||
|
PROPCACHEITEM *m_rgCachedProps;
|
||
|
DWORD m_iCachedPropsBase;
|
||
|
DWORD m_cCachedProps;
|
||
|
};
|
||
|
|
||
|
// Utility function to crash when error conditions are detected in mailmsg
|
||
|
extern DWORD g_fForceCrashOnError;
|
||
|
inline void ForceCrashIfNeeded()
|
||
|
{
|
||
|
INT *pnull = NULL;
|
||
|
if(g_fForceCrashOnError)
|
||
|
*pnull = 0;
|
||
|
}
|
||
|
#endif
|