// PrValAry.C ------------------------------------------------------------------
// Implementation of a set of functions that maintain a MAPI
// allocated array of property values.
//
// Copyright (C) Microsoft Corp. 1986-1996. All Rights Reserved.
// -----------------------------------------------------------------------------
#include "edk.h"
#include "PrValAry.h"
// -----------------------------------------------------------------------------
HRESULT PVA_HrInit(
THIS LPPropValArray pva, // Uninitialized structure to be initialized.
IN ULONG cExpandAmt, // Amount to expand array by when it gets full.
IN ULONG cProps, // Count of properties in array.
IN LPSPropValue lpPropVal) // A MAPI allocated array of properties, or NULL.
{
HRESULT hr = NOERROR;
ULONG cb = 0;
// This will validate the initial property array.
if( cProps)
{
hr = ScCountProps( cProps, lpPropVal, &cb);
if( FAILED( hr))
goto cleanup;
}
pva->cExpandAmt = cExpandAmt;
pva->cTotal = cProps;
pva->cMax = cProps;
pva->lpPVOrig = lpPropVal;
pva->lpPropVal = lpPropVal;
cleanup:
if( FAILED( hr))
memset( pva, 0, sizeof( PropValArray));
RETURN( hr);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void PVA_Destroy(
THIS LPPropValArray pva) // Structure to be destroyed.
{
if( pva->lpPropVal != pva->lpPVOrig)
MAPIFREEBUFFER( pva->lpPropVal);
MAPIFREEBUFFER( pva->lpPVOrig);
memset( pva, 0, sizeof( PropValArray));
}
// -----------------------------------------------------------------------------
// This function prepares a property for placement in the property value array.
//
// If the property is a simple type that does not point to data in another
// location we simply return.
//
// If the propery points to data contained outside of the SPropValue structure
// we make a copy of it using ScCopyProps(). This simplifies our code since
// there are many different data types and ScCopyProps() handles them all. We
// will waste the sizeof( SPropValue) bytes but it is a small price to pay for
// simple code.
// -----------------------------------------------------------------------------
static HRESULT PVA_HrPrepare(
THIS LPPropValArray pva, // Array to manipulate
IN OUT LPSPropValue* lppPropVal) // Prop val to prepare for placement in array.
{
HRESULT hr = NOERROR;
ULONG cb = 0;
ULONG cBytesCopied = 0;
LPSPropValue lpNewPropVal = NULL;
// Count the bytes needed for the new property.
hr = ScCountProps( 1, *lppPropVal, &cb);
if( FAILED( hr))
goto cleanup;
// Does this entry require extra data space?
if( cb > sizeof( SPropValue))
{ // YES, so prepare it.
// Allocate a new buffer, linked to the original, to hold the copied properties.
hr = MAPIAllocateMore( cb, pva->lpPVOrig, &lpNewPropVal);
if( FAILED( hr))
goto cleanup;
memset( lpNewPropVal, 0, cb);
// Copy the subscriber properties to the new buffer.
hr = ScCopyProps( 1, *lppPropVal, lpNewPropVal, &cBytesCopied);
if( FAILED( hr))
goto cleanup;
ASSERTERROR( cb == cBytesCopied, "ScCountProps & ScCopyProps are inconsistent!");
// Replace the caller's buffer since we have a copy of the data.
*lppPropVal = lpNewPropVal;
}
cleanup:
RETURN( hr);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
HRESULT PVA_HrInsert(
THIS LPPropValArray pva, // Array to manipulate
IN ULONG iProp, // Index of insertion point.
IN LPSPropValue lpPropVal) // Property value to insert.
{
HRESULT hr = NOERROR;
ULONG cb = 0;
ULONG cBytesCopied = 0;
LPSPropValue lpPVSlot = NULL;
LPSPropValue lpNewPropVal = NULL;
ASSERTERROR( iProp <= pva->cTotal, "Index is too large.");
// Is the array full?
if( pva->cTotal == pva->cMax)
{ // YES, the array is full.
// Increase the maximum size of the array.
pva->cMax += pva->cExpandAmt;
// Allocate a new and expanded array.
cb = pva->cMax * sizeof( SPropValue);
hr = MAPIAllocateBuffer( cb, &lpNewPropVal);
if( FAILED( hr))
goto cleanup;
// Zero newly allocated memory.
memset( lpNewPropVal, 0, cb);
// Copy full array into it, if there is something to copy.
if( pva->lpPropVal)
MoveMemory( lpNewPropVal, pva->lpPropVal, pva->cTotal * sizeof( SPropValue));
// If the full array is NOT the original MAPIAllocation free it. By retaining
// the original allocation we keep the extra data associated with it but waste
// the space occupied by the original SPropValue array. But it is worth this
// small cost to keep the code simple.
if( pva->lpPropVal != pva->lpPVOrig)
MAPIFREEBUFFER( pva->lpPropVal);
// Make the new array allocation the current array.
pva->lpPropVal = lpNewPropVal;
if( !pva->lpPVOrig)
pva->lpPVOrig = lpNewPropVal;
}
// Prepare property value to be placed in array.
hr = PVA_HrPrepare( pva, &lpPropVal);
if( FAILED( hr))
goto cleanup;
// Slot to insert new property into.
lpPVSlot = pva->lpPropVal + iProp;
// Open up a new slot for the property to insert (if not at end).
if( iProp < pva->cTotal)
MoveMemory( lpPVSlot + 1, lpPVSlot, (pva->cTotal - iProp) * sizeof( SPropValue));
// Copy the new property into the array.
MoveMemory( lpPVSlot, lpPropVal, sizeof( SPropValue));
// Increment the total array elements used.
pva->cTotal ++;
cleanup:
RETURN( hr);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
HRESULT PVA_HrModify(
THIS LPPropValArray pva, // Array to manipulate
IN ULONG iProp, // Index of insertion point.
IN LPSPropValue lpPropVal) // Property value to insert.
{
HRESULT hr = NOERROR;
// Prepare property value to be placed in array.
hr = PVA_HrPrepare( pva, &lpPropVal);
if( FAILED( hr))
goto cleanup;
// Copy the new property into the array.
MoveMemory( pva->lpPropVal + iProp, lpPropVal, sizeof( SPropValue));
cleanup:
RETURN( hr);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
HRESULT PVA_HrDelete(
THIS LPPropValArray pva, // Array to manipulate
IN ULONG iProp) // Index of property to delete.
{
LPSPropValue lpPVSlot = NULL;
// Decrement the total array elements used.
pva->cTotal --;
// Pointer to the element to be deleted.
lpPVSlot = pva->lpPropVal + iProp;
// Delete the property in the slot.
if( iProp < pva->cTotal)
MoveMemory( lpPVSlot, lpPVSlot + 1, (pva->cTotal - iProp) * sizeof( SPropValue));
// Clear the last property in the array.
memset( pva->lpPropVal + pva->cTotal, 0, sizeof( SPropValue));
return( NOERROR);
}
// -----------------------------------------------------------------------------