Windows2003-3790/inetcore/outlookexpress/wabw/wabapi/valcopy.c
2020-09-30 16:53:55 +02:00

1763 lines
48 KiB
C

/*
* VALCOPY.C
*
* Utility functions for validating, copying, and (yeech) relocating
* complex MAPI structures.
*
* For each data type there are three functions:
* ScCountXXX address-checks and calculates the size
* ScCopyXXX copies to a contiguous block of memory, which
* must be pre-allocated
* ScRelocXXX adjusts pointers, assuming that a structure in a
* contiguous block of memory has been moved
*
* Data types supported:
* NOTIFICATION (and array of), in ScCountNotifications etc.
* SPropValue (and array of), in ScCountProps etc.
*
* //$ SIZE Returning the byte count from ScRelocXXX may not be necessary.
*/
#include <_apipch.h>
#if defined (_AMD64_) || defined (_IA64_)
#define AlignProp(_cb) Align8(_cb)
#else
#define AlignProp(_cb) (_cb)
#endif
#define ALIGN_RISC 8
#define ALIGN_X86 1
// Pointer manipulation macros for use in the Reloc functions
#ifdef WIN16
#define SEG(_fp) HIWORD((DWORD)_fp)
#define OFF(_fp) LOWORD((DWORD)_fp)
#define PvRelocPv(_p,_baseOld,_baseNew) \
((LPVOID)MAKELONG(OFF(_p) - OFF(_baseOld) + OFF(_baseNew), SEG(_baseNew)))
#else
#define PvRelocPv(_p,_baseOld,_baseNew) \
((LPVOID)((LPBYTE)(_p) - (LPBYTE)(_baseOld) + (LPBYTE)(_baseNew)))
#endif
#ifdef NOTIFICATIONS // save this for notifications
STDAPI_(SCODE)
ScCountNotifications(int cntf, LPNOTIFICATION rgntf, ULONG FAR *pcb)
{
ULONG cb;
ULONG cbT;
LPNOTIFICATION pntf;
SCODE sc = S_OK;
// validate parameters
AssertSz(!cntf || !IsBadReadPtr(rgntf, sizeof(NOTIFICATION) * cntf),
TEXT("rgntf fails address check"));
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
TEXT("pcb fails address check"));
for (cb = 0, pntf = rgntf; cntf--; ++pntf)
{
if (IsBadReadPtr(pntf, sizeof(NOTIFICATION)))
{
DebugTraceArg(ScCountNotification, TEXT("pntf fails address check"));
goto badNotif;
}
cb += sizeof(NOTIFICATION);
switch (HIWORD(pntf->ulEventType))
{
case (fnevExtended >> 16):
// case (fnevSpooler >> 16):
// fnevSpooler and fnevExtended both use the EXTENDED_NOTIFICATION
// structure for their parameters
if (pntf->info.ext.cb &&
IsBadReadPtr(pntf->info.ext.pbEventParameters, (UINT)pntf->info.ext.cb))
{
DebugTraceArg(ScCountNotification, TEXT("ext.pbEventParameters fails address check"));
goto badNotif;
}
cb += AlignProp(pntf->info.ext.cb);
break;
case 0:
{
switch (LOWORD(pntf->ulEventType))
{
case (USHORT)fnevCriticalError:
{
ERROR_NOTIFICATION FAR *perr = &pntf->info.err;
if ( IsBadReadPtr( perr->lpEntryID, (UINT)perr->cbEntryID ) )
{
DebugTraceArg( ScCountNotification, TEXT("lpEntryID fails address check") );
goto badNotif;
}
cb += AlignProp(((UINT)perr->cbEntryID));
if (perr->lpMAPIError)
{
cb += AlignProp(sizeof( MAPIERROR ));
#if defined(_WINNT) && !defined(MAC)
if (perr->ulFlags & MAPI_UNICODE)
{
//$ No error check in WIN16
if (IsBadStringPtrW((LPWSTR)perr->lpMAPIError->lpszError, INFINITE))
{
DebugTraceArg(ScCountNotification, TEXT("err.MapiError.lpszError (UNICODE) fails address check"));
goto badNotif;
}
cb += AlignProp(((lstrlenW((LPWSTR)perr->lpMAPIError->lpszError) + 1)
* sizeof(WCHAR)));
if ( perr->lpMAPIError->lpszComponent )
{
if (IsBadStringPtrW((LPWSTR)perr->lpMAPIError->lpszComponent, INFINITE))
{
DebugTraceArg(ScCountNotification, TEXT("err.MapiError.lpszComponent (UNICODE) fails address check"));
goto badNotif;
}
cb += AlignProp(((lstrlenW((LPWSTR)perr->lpMAPIError->lpszComponent) + 1)
* sizeof(WCHAR)));
}
}
else
#endif
{
if (IsBadStringPtrA((LPSTR)perr->lpMAPIError->lpszError, INFINITE))
{
DebugTraceArg(ScCountNotification, TEXT("err.MapiError.lpszError (ASCII) fails address check"));
goto badNotif;
}
cb += AlignProp((lstrlenA((LPSTR)perr->lpMAPIError->lpszError) + 1));
if ( perr->lpMAPIError->lpszComponent )
{
if (IsBadStringPtrA((LPSTR)perr->lpMAPIError->lpszComponent, INFINITE))
{
DebugTraceArg(ScCountNotification, TEXT("err.MapiError.lpszError (ASCII) fails address check"));
goto badNotif;
}
cb += AlignProp((lstrlenA((LPSTR)perr->lpMAPIError->lpszComponent) + 1));
}
}
}
break;
}
case (USHORT)fnevNewMail:
{
NEWMAIL_NOTIFICATION FAR *pnew = &pntf->info.newmail;
if (IsBadReadPtr(pnew->lpEntryID, (UINT)pnew->cbEntryID))
{
DebugTraceArg(ScCountNotification, TEXT("lpEntryID fails address check"));
goto badNotif;
}
cb += AlignProp(((UINT)pnew->cbEntryID));
if (IsBadReadPtr(pnew->lpParentID, (UINT)pnew->cbParentID))
{
DebugTraceArg(ScCountNotification, TEXT("lpParentID fails address check"));
goto badNotif;
}
cb += AlignProp(((UINT)pnew->cbParentID));
if (pnew->lpszMessageClass)
{
if (pnew->ulFlags & MAPI_UNICODE)
{
#if defined(_WINNT) && !defined(MAC)
//$ No error check in WIN16
if (IsBadStringPtrW((LPWSTR)pnew->lpszMessageClass, INFINITE))
{
DebugTraceArg(ScCountNotification, TEXT("newmail.lpszMessageClass (UNICODE) fails address check"));
goto badNotif;
}
#endif
cb += AlignProp(((lstrlenW((LPWSTR)pnew->lpszMessageClass) + 1)
* sizeof(WCHAR)));
}
else
{
if (IsBadStringPtrA((LPSTR)pnew->lpszMessageClass, INFINITE))
{
DebugTraceArg(ScCountNotification, TEXT("newmail.lpszMessageClass (ASCII) fails address check"));
goto badNotif;
}
cb += AlignProp((lstrlenA((LPSTR)pnew->lpszMessageClass) + 1));
}
}
break;
}
case (USHORT)fnevObjectCreated:
case (USHORT)fnevObjectDeleted:
case (USHORT)fnevObjectModified:
case (USHORT)fnevObjectMoved:
case (USHORT)fnevObjectCopied:
case (USHORT)fnevSearchComplete:
{
OBJECT_NOTIFICATION FAR *pobj = &pntf->info.obj;
if (pobj->cbEntryID)
{
if (IsBadReadPtr(pobj->lpEntryID, (UINT)pobj->cbEntryID))
{
DebugTraceArg(ScCountNotifications, TEXT("obj.lpEntryID fails address check"));
goto badNotif;
}
cb += AlignProp(pobj->cbEntryID);
}
if (pobj->cbParentID)
{
if (IsBadReadPtr(pobj->lpParentID, (UINT)pobj->cbParentID))
{
DebugTraceArg(ScCountNotifications, TEXT("obj.lpParentID fails address check"));
goto badNotif;
}
cb += AlignProp(pobj->cbParentID);
}
if (pobj->cbOldID)
{
if (IsBadReadPtr(pobj->lpOldID, (UINT)pobj->cbOldID))
{
DebugTraceArg(ScCountNotifications, TEXT("obj.lpOldID fails address check"));
goto badNotif;
}
cb += AlignProp(pobj->cbOldID);
}
if (pobj->cbOldParentID)
{
if (IsBadReadPtr(pobj->lpOldParentID, (UINT)pobj->cbOldParentID))
{
DebugTraceArg(ScCountNotifications, TEXT("obj.lpOldParentID fails address check"));
goto badNotif;
}
cb += AlignProp(pobj->cbOldParentID);
}
if (pobj->lpPropTagArray)
{
if (IsBadReadPtr(pobj->lpPropTagArray, sizeof(ULONG)) ||
IsBadReadPtr(pobj->lpPropTagArray,
offsetof(SPropTagArray, aulPropTag) +
(UINT)pobj->lpPropTagArray->cValues * sizeof(ULONG)))
{
DebugTraceArg(ScCountNotifications, TEXT("obj.lpPropTagArray fails address check"));
goto badNotif;
}
cb += AlignProp(offsetof(SPropTagArray, aulPropTag) +
pobj->lpPropTagArray->cValues * sizeof(ULONG));
}
break;
}
case (USHORT)fnevTableModified:
{
TABLE_NOTIFICATION FAR *ptn = &pntf->info.tab;
UINT n = (UINT) ptn->ulTableEvent;
if (n != TABLE_CHANGED &&
n != TABLE_RELOAD &&
n != TABLE_ERROR &&
n != TABLE_ROW_ADDED &&
n != TABLE_ROW_DELETED &&
n != TABLE_ROW_MODIFIED &&
n != TABLE_SORT_DONE &&
n != TABLE_RESTRICT_DONE &&
n != TABLE_SETCOL_DONE)
{
DebugTraceArg(ScCountNotifications, TEXT("invalid tab.ulTableEvent"));
goto badNotif;
}
if (ptn->propIndex.ulPropTag)
{
if (sc = ScCountProps(1, &ptn->propIndex, &cbT))
goto ret;
cb += cbT;
}
if (ptn->propPrior.ulPropTag)
{
if (sc = ScCountProps(1, &ptn->propPrior, &cbT))
goto ret;
cb += cbT;
}
if (ptn->row.cValues)
{
if (sc = ScCountProps((int)ptn->row.cValues, ptn->row.lpProps,
&cbT))
goto ret;
cb += cbT;
}
else if (ptn->row.lpProps)
{
DebugTraceArg(ScCountNotifications, TEXT("non-NULL row.lpProps with zero row.cValues in table notification"));
goto badNotif;
}
break;
}
case (USHORT)fnevStatusObjectModified:
{
STATUS_OBJECT_NOTIFICATION FAR *pstat = &pntf->info.statobj;
if (pstat->cbEntryID)
{
if (IsBadReadPtr(pstat->lpEntryID, (UINT)pstat->cbEntryID))
{
DebugTraceArg(ScCountNotifications, TEXT("statobj.lpEntryID fails address check"));
goto badNotif;
}
cb += AlignProp(pstat->cbEntryID);
}
if (pstat->cValues)
{
if (sc = ScCountProps((int)pstat->cValues,
pstat->lpPropVals, &cbT))
goto ret;
cb += cbT;
}
break;
}
default:
DebugTraceArg(ScCountNotification, TEXT("invalid ulEventType"));
goto badNotif;
}
break;
}
default:
DebugTraceArg(ScCountNotification, TEXT("invalid ulEventType"));
goto badNotif;
}
}
if (pcb)
*pcb = cb;
ret:
DebugTraceSc(ScCountNotifications, sc);
return sc;
badNotif:
// trace already issued
return E_INVALIDARG;
}
STDAPI_(SCODE)
ScCopyNotifications(int cntf, LPNOTIFICATION rgntf, LPVOID pvDst,
ULONG FAR *pcb)
{
LPBYTE pb = pvDst;
ULONG cb = 0;
ULONG cbT;
LPNOTIFICATION pntf;
LPNOTIFICATION pntfDst;
SCODE sc = S_OK;
// validate parameters
AssertSz(!cntf || !IsBadReadPtr(rgntf, sizeof(NOTIFICATION) * cntf),
TEXT("rgntf fails address check"));
AssertSz(!cntf || !IsBadWritePtr(pvDst, sizeof(NOTIFICATION) * cntf),
TEXT("pvDst fails address check"));
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
TEXT("pcb fails address check"));
cb = cntf * sizeof(NOTIFICATION);
MemCopy(pvDst, rgntf, (UINT)cb);
pb = (LPBYTE)pvDst + cb;
for (pntf = rgntf, pntfDst = (LPNOTIFICATION)pvDst;
cntf--;
++pntf, ++pntfDst)
{
switch (HIWORD(pntf->ulEventType))
{
case (fnevExtended >> 16):
// case (fnevSpooler >> 16):
if (pntf->info.ext.cb)
{
pntfDst->info.ext.pbEventParameters = pb;
cbT = pntf->info.ext.cb;
MemCopy(pb, pntf->info.ext.pbEventParameters, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
break;
case 0:
{
switch (LOWORD(pntf->ulEventType))
{
case (USHORT)fnevCriticalError:
{
ERROR_NOTIFICATION FAR *perr = &pntf->info.err;
if ( perr->cbEntryID )
{
pntfDst->info.err.lpEntryID = (LPENTRYID)pb;
cbT = perr->cbEntryID;
MemCopy(pb, perr->lpEntryID, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if ( perr->lpMAPIError )
{
pntfDst->info.err.lpMAPIError = (LPMAPIERROR)pb;
cbT = sizeof(MAPIERROR);
MemCopy( pb, perr->lpMAPIError, sizeof( MAPIERROR ) );
pb += AlignProp(cbT);
cb += AlignProp(cbT);
if (perr->lpMAPIError->lpszError)
{
#ifdef _WINNT
if (perr->ulFlags & MAPI_UNICODE)
{
cbT = (lstrlenW((LPWSTR)perr->lpMAPIError->lpszError)
+ 1) * sizeof(WCHAR);
}
else
#endif
{
cbT = lstrlenA((LPSTR)perr->lpMAPIError->lpszError) + 1;
}
pntfDst->info.err.lpMAPIError->lpszError = (LPSTR)pb;
MemCopy(pb, perr->lpMAPIError->lpszError, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (perr->lpMAPIError->lpszComponent)
{
#ifdef _WINNT
if (perr->ulFlags & MAPI_UNICODE)
{
cbT = (lstrlenW((LPWSTR)perr->lpMAPIError->lpszComponent)
+ 1) * sizeof(WCHAR);
}
else
#endif
{
cbT = lstrlenA((LPSTR)perr->lpMAPIError->lpszComponent) + 1;
}
pntfDst->info.err.lpMAPIError->lpszComponent = pb;
MemCopy(pb, perr->lpMAPIError->lpszComponent, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
}
break;
}
case (USHORT)fnevNewMail:
{
NEWMAIL_NOTIFICATION FAR *pnew = &pntf->info.newmail;
if (pnew->cbEntryID)
{
pntfDst->info.newmail.lpEntryID = (LPENTRYID)pb;
cbT = pnew->cbEntryID;
MemCopy(pb, pnew->lpEntryID, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (pnew->cbParentID)
{
pntfDst->info.newmail.lpParentID = (LPENTRYID)pb;
cbT = pnew->cbParentID;
MemCopy(pb, pnew->lpParentID, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (pnew->lpszMessageClass)
{
if (pnew->ulFlags & MAPI_UNICODE)
cbT = (lstrlenW((LPWSTR)pnew->lpszMessageClass) + 1)
* sizeof(WCHAR);
else
cbT = lstrlenA((LPSTR)pnew->lpszMessageClass) + 1;
pntfDst->info.newmail.lpszMessageClass = (LPTSTR)pb;
MemCopy(pb, pnew->lpszMessageClass, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
break;
}
case (USHORT)fnevObjectCreated:
case (USHORT)fnevObjectDeleted:
case (USHORT)fnevObjectModified:
case (USHORT)fnevObjectMoved:
case (USHORT)fnevObjectCopied:
case (USHORT)fnevSearchComplete:
{
OBJECT_NOTIFICATION FAR *pobj = &pntf->info.obj;
if (pobj->cbEntryID)
{
pntfDst->info.obj.lpEntryID = (LPENTRYID)pb;
cbT = pobj->cbEntryID;
MemCopy(pb, pobj->lpEntryID, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (pobj->cbParentID)
{
pntfDst->info.obj.lpParentID = (LPENTRYID)pb;
cbT = pobj->cbParentID;
MemCopy(pb, pobj->lpParentID, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (pobj->cbOldID)
{
pntfDst->info.obj.lpOldID = (LPENTRYID)pb;
cbT = pobj->cbOldID;
MemCopy(pb, pobj->lpOldID, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (pobj->cbOldParentID)
{
pntfDst->info.obj.lpOldParentID = (LPENTRYID)pb;
cbT = pobj->cbOldParentID;
MemCopy(pb, pobj->lpOldParentID, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (pobj->lpPropTagArray)
{
cbT = offsetof(SPropTagArray, aulPropTag) +
pobj->lpPropTagArray->cValues * sizeof(ULONG);
pntfDst->info.obj.lpPropTagArray = (LPSPropTagArray)pb;
MemCopy(pb, pobj->lpPropTagArray, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
break;
}
case (USHORT)fnevTableModified:
{
TABLE_NOTIFICATION FAR *ptn = &pntf->info.tab;
if (ptn->propIndex.ulPropTag)
{
// Wastes 16 bytes when the property doesn't have a tail
if (sc = ScCopyProps(1, &ptn->propIndex, pb, &cbT))
goto ret;
//
// This was once a straight structure assignment. However, on RISC platforms
// if pntfDst is not on an 8-byte boundary, this raises a Datatype
// Misalignment Exception. Changed this to a memcpy in order to not worry
// about alignment and not cause any extra exception handling.
//
memcpy(&(pntfDst->info.tab.propIndex), (LPSPropValue)pb, sizeof(SPropValue));
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (ptn->propPrior.ulPropTag)
{
// Wastes 16 bytes when the property doesn't have a tail
if (sc = ScCopyProps(1, &ptn->propPrior, pb, &cbT))
goto ret;
//
// This was once a straight structure assignment. However, on RISC platforms
// if pntfDst is not on an 8-byte boundary, this raises a Datatype
// Misalignment Exception. Changed this to a memcpy in order to not worry
// about alignment and not cause any extra exception handling.
//
memcpy(&(pntfDst->info.tab.propPrior), (LPSPropValue)pb, sizeof(SPropValue));
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (ptn->row.cValues)
{
pntfDst->info.tab.row.lpProps = (LPSPropValue)pb;
if (sc = ScCopyProps((int)ptn->row.cValues, ptn->row.lpProps, pb, &cbT))
goto ret;
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
break;
}
case (USHORT)fnevStatusObjectModified:
{
STATUS_OBJECT_NOTIFICATION FAR *pstat = &pntf->info.statobj;
if (pstat->cbEntryID)
{
pntfDst->info.statobj.lpEntryID = (LPENTRYID)pb;
cbT = pstat->cbEntryID;
MemCopy(pb, pstat->lpEntryID, (UINT)cbT);
pb += AlignProp(cbT);
cb += AlignProp(cbT);
}
if (pstat->cValues)
{
pntfDst->info.statobj.lpPropVals = (LPSPropValue)pb;
if (sc = ScCopyProps((int)pstat->cValues,
pstat->lpPropVals, pb, &cbT))
goto ret;
pb += cbT;
cb += cbT;
}
break;
}
default:
DebugTraceArg(ScCopyNotification, TEXT("invalid ulEventType"));
goto badNotif;
}
break;
}
default:
DebugTraceArg(ScCopyNotification, TEXT("invalid ulEventType"));
goto badNotif;
}
}
if (pcb)
*pcb = (ULONG)cb;
ret:
DebugTraceSc(ScCopyNotifications, sc);
return sc;
badNotif:
// trace already issued
return E_INVALIDARG;
#undef COPY
}
STDAPI_(SCODE)
ScRelocNotifications(int cntf, LPNOTIFICATION rgntf, LPVOID pvBaseOld,
LPVOID pvBaseNew, ULONG FAR *pcb)
{
ULONG cb;
ULONG cbT;
LPNOTIFICATION pntf;
SCODE sc = S_OK;
AssertSz(!cntf || !IsBadReadPtr(rgntf, sizeof(NOTIFICATION) * cntf),
TEXT("rgntf fails address check"));
AssertSz(pvBaseOld, TEXT("pvBaseOld fails address check"));
AssertSz(!IsBadWritePtr(pvBaseNew, sizeof(LPVOID)),
TEXT("pvBaseNew fails address check"));
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
TEXT("pcb fails address check"));
cb = cntf * sizeof(NOTIFICATION);
for (pntf = rgntf; cntf--; ++pntf)
{
switch (HIWORD(pntf->ulEventType))
{
case (fnevExtended >> 16):
// case (fnevSpooler >> 16):
if (pntf->info.ext.cb)
{
pntf->info.ext.pbEventParameters =
PvRelocPv(pntf->info.ext.pbEventParameters, pvBaseOld,
pvBaseNew);
cb += AlignProp(pntf->info.ext.cb);
}
break;
case 0:
{
switch (LOWORD(pntf->ulEventType))
{
case (USHORT)fnevCriticalError:
{
ERROR_NOTIFICATION FAR *perr = &pntf->info.err;
if ( perr->lpEntryID )
{
perr->lpEntryID = PvRelocPv( perr->lpEntryID, pvBaseOld,
pvBaseNew );
cb += AlignProp( (UINT)perr->cbEntryID );
}
if ( perr->lpMAPIError )
{
perr->lpMAPIError = PvRelocPv( perr->lpMAPIError, pvBaseOld,
pvBaseNew );
if (perr->lpMAPIError->lpszError)
{
perr->lpMAPIError->lpszError = PvRelocPv(
perr->lpMAPIError->lpszError, pvBaseOld,
pvBaseNew );
#ifdef _WINNT
if (perr->ulFlags & MAPI_UNICODE)
cb += AlignProp((lstrlenW((LPWSTR)perr->lpMAPIError->lpszError)
+ 1) * sizeof(WCHAR));
else
#endif
cb += AlignProp(lstrlenA((LPSTR)perr->lpMAPIError->lpszError) + 1);
}
if (perr->lpMAPIError->lpszComponent)
{
perr->lpMAPIError->lpszComponent = PvRelocPv(
perr->lpMAPIError->lpszComponent, pvBaseOld,
pvBaseNew );
#ifdef _WINNT
if (perr->ulFlags & MAPI_UNICODE)
cb += AlignProp((lstrlenW((LPWSTR)perr->lpMAPIError->lpszComponent) + 1)
* sizeof(WCHAR));
else
#endif
cb += AlignProp(lstrlenA((LPSTR)perr->lpMAPIError->lpszComponent) + 1);
}
}
}
case (USHORT)fnevNewMail:
{
NEWMAIL_NOTIFICATION FAR *pnew = &pntf->info.newmail;
if (pnew->lpEntryID)
{
pnew->lpEntryID = PvRelocPv(pnew->lpEntryID, pvBaseOld,
pvBaseNew);
cb += AlignProp((UINT)pnew->cbEntryID);
}
if (pnew->lpParentID)
{
pnew->lpParentID = PvRelocPv(pnew->lpParentID, pvBaseOld,
pvBaseNew);
cb += AlignProp((UINT)pnew->cbParentID);
}
if (pnew->lpszMessageClass)
{
pnew->lpszMessageClass = PvRelocPv(pnew->lpszMessageClass,
pvBaseOld, pvBaseNew);
if (pnew->ulFlags & MAPI_UNICODE)
cbT = (lstrlenW((LPWSTR)pnew->lpszMessageClass) + 1)
* sizeof(WCHAR);
else
cbT = lstrlenA((LPSTR)pnew->lpszMessageClass) + 1;
cb += AlignProp(cbT);
}
break;
}
case (USHORT)fnevObjectCreated:
case (USHORT)fnevObjectDeleted:
case (USHORT)fnevObjectModified:
case (USHORT)fnevObjectMoved:
case (USHORT)fnevObjectCopied:
case (USHORT)fnevSearchComplete:
{
OBJECT_NOTIFICATION FAR *pobj = &pntf->info.obj;
if (pobj->lpEntryID)
{
pobj->lpEntryID = PvRelocPv(pobj->lpEntryID, pvBaseOld,
pvBaseNew);
cb += AlignProp(pobj->cbEntryID);
}
if (pobj->lpParentID)
{
pobj->lpParentID = PvRelocPv(pobj->lpParentID, pvBaseOld,
pvBaseNew);
cb += AlignProp(pobj->cbParentID);
}
if (pobj->lpOldID)
{
pobj->lpOldID = PvRelocPv(pobj->lpOldID, pvBaseOld,
pvBaseNew);
cb += AlignProp(pobj->cbOldID);
}
if (pobj->lpOldParentID)
{
pobj->lpOldParentID = PvRelocPv(pobj->lpOldParentID, pvBaseOld,
pvBaseNew);
cb += AlignProp(pobj->cbOldParentID);
}
if (pobj->lpPropTagArray)
{
pobj->lpPropTagArray = PvRelocPv(pobj->lpPropTagArray,
pvBaseOld, pvBaseNew);
cb += offsetof(SPropTagArray, aulPropTag) +
pobj->lpPropTagArray->cValues * sizeof(ULONG);
}
break;
}
case (USHORT)fnevTableModified:
{
TABLE_NOTIFICATION FAR *ptn = &pntf->info.tab;
Assert (FIsAligned (&ptn->propIndex));
if (ptn->propIndex.ulPropTag)
{
if (sc = ScRelocProps(1, &ptn->propIndex, pvBaseOld,
pvBaseNew, &cbT))
goto ret;
cb += cbT;
}
Assert (FIsAligned (&ptn->propPrior));
if (ptn->propPrior.ulPropTag)
{
if (sc = ScRelocProps(1, &ptn->propPrior, pvBaseOld,
pvBaseNew, &cbT))
goto ret;
cb += cbT;
}
if (ptn->row.cValues)
{
Assert (FIsAligned (ptn->row.lpProps));
ptn->row.lpProps = PvRelocPv(ptn->row.lpProps,
pvBaseOld, pvBaseNew);
if (sc = ScRelocProps((int)ptn->row.cValues, ptn->row.lpProps,
pvBaseOld, pvBaseNew, &cbT))
goto ret;
cb += cbT;
}
break;
}
case (USHORT)fnevStatusObjectModified:
{
STATUS_OBJECT_NOTIFICATION FAR *pstat = &pntf->info.statobj;
if (pstat->lpEntryID)
{
pstat->lpEntryID = PvRelocPv(pstat->lpEntryID, pvBaseOld,
pvBaseNew);
// Whoa, this is not sufficient to buffer the size of
// the entryid. If the entryid is not aligned, then the
// the properties that follow will not be aligned either.
//
Assert (FIsAligned (pstat->lpEntryID));
cb += AlignProp(pstat->cbEntryID);
}
if (pstat->cValues)
{
pstat->lpPropVals = PvRelocPv(pstat->lpPropVals,
pvBaseOld, pvBaseNew);
Assert (FIsAligned (pstat->lpPropVals));
if (sc = ScRelocProps((int)pstat->cValues, pstat->lpPropVals,
pvBaseOld, pvBaseNew, &cbT))
goto ret;
cb += cbT;
}
break;
}
default:
DebugTraceArg(ScRelocNotification, TEXT("invalid ulEventType"));
goto badNotif;
}
break;
}
default:
DebugTraceArg(ScRelocNotification, TEXT("invalid ulEventType"));
goto badNotif;
}
}
if (pcb)
*pcb = cb;
ret:
DebugTraceSc(ScRelocNotifications, sc);
return sc;
badNotif:
// trace already issued
return E_INVALIDARG;
}
#endif // NOTIFICATIONS
STDAPI_(LPSPropValue)
LpValFindProp( ULONG ulPropTag, ULONG cprop, LPSPropValue rgprop)
{
// Mutate the property tag to a property ID
ulPropTag = PROP_ID(ulPropTag);
while (cprop--)
{
Assert( !IsBadReadPtr( rgprop, sizeof(SPropValue)));
if (PROP_ID(rgprop->ulPropTag) == ulPropTag)
{
return rgprop;
}
rgprop++;
}
// No match was found so return NULL.
return NULL;
}
/*
* ScCountPropsEx()
*
* Internal routine that computes the size required
* to hold a given propval array based on specified alignment
*/
SCODE
ScCountPropsEx(int cprop, LPSPropValue rgprop, ULONG ulAlign, ULONG FAR *pcb)
{
LPSPropValue pprop;
ULONG cb = 0;
ULONG cbMV;
int iValue;
#define Align(_cb) ((ULONG)( ((DWORD_PTR) ((_cb) + (ulAlign-1))) & ~(((DWORD_PTR) ulAlign-1))))
// validate parameters
AssertSz(ulAlign && ulAlign <= ALIGN_RISC,
TEXT("invalid alignment value"));
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
TEXT("pcb fails address check"));
//$ SIZE Some of the multi-valued cases could be collapsed if we don't
//$ mind assuming that the counts and pointers are in the same place.
if ( (rgprop && !cprop)
|| IsBadReadPtr(rgprop, cprop*sizeof(SPropValue)))
{
DebugTraceArg(ScCountProps, TEXT("rgprop fails address check"));
return MAPI_E_INVALID_PARAMETER;
}
for (pprop = rgprop; cprop--; ++pprop)
{
ULONG ulID = PROP_ID(pprop->ulPropTag);
ULONG ulType = PROP_TYPE(pprop->ulPropTag);
// Check for valid PROP_ID
if ( (ulID == PROP_ID_INVALID)
|| ((ulType == PT_NULL) && (ulID != PROP_ID_NULL))
|| ((ulID == PROP_ID_NULL) && (ulType != PT_NULL) && (ulType != PT_ERROR)))
return MAPI_E_INVALID_PARAMETER;
// Check for valid PROP_TYPE and count memory consumed
cb += sizeof(SPropValue);
switch ( PROP_TYPE(pprop->ulPropTag) )
{
case PT_UNSPECIFIED:
default:
DebugTrace( TEXT("ScCountProps: Unknown property type %s (index %d)\n"), SzDecodeUlPropTag(pprop->ulPropTag), pprop - rgprop);
return MAPI_E_INVALID_PARAMETER;
case PT_I2:
case PT_LONG:
case PT_R4:
case PT_APPTIME:
case PT_DOUBLE:
case PT_BOOLEAN:
case PT_CURRENCY:
case PT_SYSTIME:
case PT_I8:
case PT_ERROR:
case PT_OBJECT:
case PT_NULL:
break;
case PT_CLSID:
if (IsBadReadPtr(pprop->Value.lpguid, sizeof(GUID)))
goto badProp;
cb += Align(sizeof(GUID));
break;
case PT_BINARY:
//$Hack: IsBadReadPtr works funny under Win16.
//$Hack: It doesn't handle the case of 0 cb, and
//$Hack: non-0 lpb.
if (pprop->Value.bin.cb && IsBadReadPtr( pprop->Value.bin.lpb
, (UINT) (pprop->Value.bin.cb)))
goto badProp;
cb += Align(pprop->Value.bin.cb);
break;
case PT_STRING8:
if (IsBadStringPtrA(pprop->Value.lpszA, INFINITE))
goto badProp;
cb += Align((lstrlenA( pprop->Value.lpszA ) + 1) * sizeof(CHAR));
break;
case PT_UNICODE:
#if defined(WIN32) && !defined(MAC)
//$ No validation code available on Win16
if (IsBadStringPtrW(pprop->Value.lpszW, INFINITE))
goto badProp;
#endif
cb += Align((lstrlenW( pprop->Value.lpszW ) + 1) * sizeof(WCHAR));
break;
// Note! MVxxx.cValues may NOT be zero (DCR 2789).
case PT_MV_I2:
if ( !(cbMV = pprop->Value.MVi.cValues * sizeof(short int))
|| IsBadReadPtr(pprop->Value.MVi.lpi, (UINT) cbMV))
goto badProp;
cb += Align(cbMV);
break;
case PT_MV_LONG:
if ( !(cbMV = pprop->Value.MVl.cValues * sizeof(LONG))
|| IsBadReadPtr(pprop->Value.MVl.lpl, (UINT) cbMV))
goto badProp;
cb += Align(cbMV);
break;
case PT_MV_R4:
if ( !(cbMV = pprop->Value.MVflt.cValues * sizeof(float))
|| IsBadReadPtr(pprop->Value.MVflt.lpflt, (UINT) cbMV))
goto badProp;
cb += Align(cbMV);
break;
case PT_MV_APPTIME:
if ( !(cbMV = pprop->Value.MVat.cValues * sizeof(double))
|| IsBadReadPtr(pprop->Value.MVat.lpat, (UINT) cbMV))
goto badProp;
cb += cbMV;
break;
case PT_MV_DOUBLE:
if ( !(cbMV = pprop->Value.MVdbl.cValues * sizeof(double))
|| IsBadReadPtr(pprop->Value.MVdbl.lpdbl, (UINT) cbMV))
goto badProp;
cb += cbMV;
break;
case PT_MV_CURRENCY:
if ( !(cbMV = pprop->Value.MVcur.cValues * sizeof(CURRENCY))
|| IsBadReadPtr(pprop->Value.MVcur.lpcur, (UINT) cbMV))
goto badProp;
cb += cbMV;
break;
case PT_MV_SYSTIME:
if ( !(cbMV = pprop->Value.MVft.cValues * sizeof(FILETIME))
|| IsBadReadPtr(pprop->Value.MVft.lpft, (UINT) cbMV))
goto badProp;
cb += cbMV;
break;
case PT_MV_CLSID:
if ( !(cbMV = pprop->Value.MVguid.cValues * sizeof(GUID))
|| IsBadReadPtr(pprop->Value.MVguid.lpguid, (UINT) cbMV))
goto badProp;
cb += cbMV;
break;
case PT_MV_I8:
if ( !(cbMV = pprop->Value.MVli.cValues * sizeof(LARGE_INTEGER))
|| IsBadReadPtr(pprop->Value.MVli.lpli, (UINT) cbMV))
goto badProp;
cb += cbMV;
break;
case PT_MV_BINARY:
if ( !(cbMV = pprop->Value.MVbin.cValues * sizeof(SBinary))
|| IsBadReadPtr(pprop->Value.MVbin.lpbin, (UINT) cbMV))
goto badProp;
Assert(Align(cbMV) == cbMV);
cb += cbMV;
for ( iValue = 0;
(ULONG)iValue < pprop->Value.MVbin.cValues;
iValue++ )
{
if (IsBadReadPtr(pprop->Value.MVbin.lpbin[iValue].lpb,
(UINT)pprop->Value.MVbin.lpbin[iValue].cb))
goto badProp;
cb += Align(pprop->Value.MVbin.lpbin[iValue].cb);
}
break;
case PT_MV_STRING8:
if ( !(cbMV = pprop->Value.MVszA.cValues * sizeof(LPVOID))
|| IsBadReadPtr(pprop->Value.MVszA.lppszA, (UINT) cbMV))
goto badProp;
cb += cbMV;
for ( iValue = 0;
(ULONG)iValue < pprop->Value.MVszA.cValues;
iValue++ )
{
if (IsBadStringPtrA(pprop->Value.MVszA.lppszA[iValue],
INFINITE))
goto badProp;
cb += lstrlenA(pprop->Value.MVszA.lppszA[iValue]) + 1;
}
cb = Align(cb);
break;
case PT_MV_UNICODE:
if ( !(cbMV = pprop->Value.MVszW.cValues * sizeof(LPVOID))
|| IsBadReadPtr(pprop->Value.MVszW.lppszW, (UINT) cbMV))
goto badProp;
cb += cbMV;
for ( iValue = 0;
(ULONG)iValue < pprop->Value.MVszW.cValues;
iValue++ )
{
#if defined(WIN32) && !defined(MAC)
//$ No validation on Win16
if (IsBadStringPtrW(pprop->Value.MVszW.lppszW[iValue], INFINITE))
goto badProp;
#endif
cb += (lstrlenW(pprop->Value.MVszW.lppszW[iValue]) + 1)
* sizeof(WCHAR);
}
cb = Align(cb);
break;
}
}
if (pcb)
{
Assert(!IsBadWritePtr(pcb, sizeof(ULONG)));
*pcb = cb;
}
return S_OK;
badProp:
DebugTrace( TEXT("ScCountProps: Unreadable property %s (index %d)\n"), SzDecodeUlPropTag(pprop->ulPropTag), pprop - rgprop);
return MAPI_E_INVALID_PARAMETER;
#undef Align
}
STDAPI_(SCODE)
ScCountProps(int cprop, LPSPropValue rgprop, ULONG FAR *pcb)
{
#if defined (_AMD64_) || defined(_IA64_)
return ScCountPropsEx( cprop, rgprop, ALIGN_RISC, pcb );
#else
return ScCountPropsEx( cprop, rgprop, ALIGN_X86, pcb );
#endif
}
STDAPI_(SCODE)
ScCopyProps(int cprop, LPSPropValue rgprop, LPVOID pvDst, ULONG FAR *pcb)
{
LPSPropValue pprop;
LPSPropValue ppropDst;
ULONG cb;
ULONG cbMV;
LPBYTE pb;
UINT cbT;
int iValue;
// validate parameters
AssertSz(!cprop || !IsBadReadPtr(rgprop, sizeof(SPropValue) * cprop),
TEXT("rgprop fails address check"));
AssertSz(!cprop || !IsBadWritePtr(pvDst, sizeof(SPropValue) * cprop),
TEXT("pvDst fails address check"));
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
TEXT("pcb fails address check"));
//$ SIZE Some of the multi-valued cases could be collapsed if we don't
//$ mind assuming that the counts and pointers are in the same place.
cb = cprop * sizeof(SPropValue);
MemCopy(pvDst, rgprop, (UINT)cb);
pb = (LPBYTE)pvDst + cb;
for (pprop = rgprop, ppropDst = pvDst; cprop--; ++pprop, ++ppropDst)
{
// Tricky: common code after the switch increments pb and cb
// by the amount copied. If no increment is necessary, the case
// uses 'continue' rather than 'break' to exit the switch, thus
// skipping the increment -- AND any other code which may be
// added after the switch.
switch ( PROP_TYPE(pprop->ulPropTag) )
{
default:
DebugTrace( TEXT("ScCopyProps: Unknown property type %s (index %d)\n"), SzDecodeUlPropTag(pprop->ulPropTag), pprop - rgprop);
return E_INVALIDARG;
case PT_I2:
case PT_LONG:
case PT_R4:
case PT_APPTIME:
case PT_DOUBLE:
case PT_BOOLEAN:
case PT_CURRENCY:
case PT_SYSTIME:
case PT_I8:
case PT_ERROR:
case PT_OBJECT:
case PT_NULL:
continue; // nothing to add
case PT_CLSID:
ppropDst->Value.lpguid = (LPGUID) pb;
cbT = sizeof(GUID);
MemCopy(pb, (LPBYTE) pprop->Value.lpguid, cbT);
break;
case PT_BINARY:
ppropDst->Value.bin.lpb = pb;
cbT = (UINT)pprop->Value.bin.cb;
MemCopy(pb, pprop->Value.bin.lpb, cbT);
break;
case PT_STRING8:
ppropDst->Value.lpszA = (LPSTR)pb;
cbT = lstrlenA( pprop->Value.lpszA ) + 1;
MemCopy(pb, pprop->Value.lpszA, cbT);
break;
case PT_UNICODE:
ppropDst->Value.lpszW = (LPWSTR)pb;
cbT = (lstrlenW( pprop->Value.lpszW ) + 1) * sizeof(WCHAR);
MemCopy(pb, pprop->Value.lpszW, cbT);
break;
case PT_MV_I2:
ppropDst->Value.MVi.lpi = (short int FAR *)pb;
cbT = (UINT)pprop->Value.MVi.cValues * sizeof(short int);
MemCopy(pb, pprop->Value.MVi.lpi, cbT);
break;
case PT_MV_LONG:
ppropDst->Value.MVl.lpl = (LONG FAR *)pb;
cbT = (UINT)pprop->Value.MVl.cValues * sizeof(LONG);
MemCopy(pb, pprop->Value.MVl.lpl, cbT);
break;
case PT_MV_R4:
ppropDst->Value.MVflt.lpflt = (float FAR *)pb;
cbT = (UINT)pprop->Value.MVflt.cValues * sizeof(float);
MemCopy(pb, pprop->Value.MVflt.lpflt, cbT);
break;
case PT_MV_APPTIME:
ppropDst->Value.MVat.lpat = (double FAR *)pb;
cbT = (UINT)pprop->Value.MVat.cValues * sizeof(double);
MemCopy(pb, pprop->Value.MVat.lpat, cbT);
break;
case PT_MV_DOUBLE:
ppropDst->Value.MVdbl.lpdbl = (double FAR *)pb;
cbT = (UINT)pprop->Value.MVdbl.cValues * sizeof(double);
MemCopy(pb, pprop->Value.MVdbl.lpdbl, cbT);
break;
case PT_MV_CURRENCY:
ppropDst->Value.MVcur.lpcur = (CURRENCY FAR *)pb;
cbT = (UINT)pprop->Value.MVcur.cValues * sizeof(CURRENCY);
MemCopy(pb, pprop->Value.MVcur.lpcur, cbT);
break;
case PT_MV_SYSTIME:
ppropDst->Value.MVft.lpft = (FILETIME FAR *)pb;
cbT = (UINT)pprop->Value.MVft.cValues * sizeof(FILETIME);
MemCopy(pb, pprop->Value.MVft.lpft, cbT);
break;
case PT_MV_CLSID:
ppropDst->Value.MVguid.lpguid = (GUID FAR *)pb;
cbT = (UINT)pprop->Value.MVguid.cValues * sizeof(GUID);
MemCopy(pb, pprop->Value.MVguid.lpguid, cbT);
break;
case PT_MV_I8:
ppropDst->Value.MVli.lpli = (LARGE_INTEGER FAR *)pb;
cbT = (UINT)pprop->Value.MVli.cValues * sizeof(LARGE_INTEGER);
MemCopy(pb, pprop->Value.MVli.lpli, cbT);
break;
case PT_MV_BINARY:
ppropDst->Value.MVbin.lpbin = (SBinary *) pb;
cbMV = pprop->Value.MVbin.cValues * sizeof(SBinary);
pb += cbMV;
cb += cbMV;
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVbin.cValues;
iValue++)
{
ppropDst->Value.MVbin.lpbin[iValue].lpb = pb;
cbT = (UINT)pprop->Value.MVbin.lpbin[iValue].cb;
ppropDst->Value.MVbin.lpbin[iValue].cb = (ULONG)cbT;
MemCopy(pb, pprop->Value.MVbin.lpbin[iValue].lpb, cbT);
cbT = AlignProp(cbT);
cb += cbT;
pb += cbT;
}
continue; // already updated, don't do it again
case PT_MV_STRING8:
ppropDst->Value.MVszA.lppszA = (LPSTR *) pb;
cbMV = pprop->Value.MVszA.cValues * sizeof(LPSTR);
pb += cbMV;
cb += cbMV;
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVszA.cValues;
iValue++)
{
ppropDst->Value.MVszA.lppszA[iValue] = (LPSTR)pb;
cbT = lstrlenA(pprop->Value.MVszA.lppszA[iValue]) + 1;
MemCopy(pb, pprop->Value.MVszA.lppszA[iValue], cbT);
pb += cbT;
cb += cbT;
}
cbT = (UINT)AlignProp(cb);
pb += cbT - cb;
cb = cbT;
continue; // already updated, don't do it again
case PT_MV_UNICODE:
ppropDst->Value.MVszW.lppszW = (LPWSTR *) pb;
cbMV = pprop->Value.MVszW.cValues * sizeof(LPWSTR);
pb += cbMV;
cb += cbMV;
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVszW.cValues;
iValue++)
{
ppropDst->Value.MVszW.lppszW[iValue] = (LPWSTR)pb;
cbT = (lstrlenW(pprop->Value.MVszW.lppszW[iValue]) + 1)
* sizeof(WCHAR);
MemCopy(pb, pprop->Value.MVszW.lppszW[iValue], cbT);
pb += cbT;
cb += cbT;
}
cbT = (UINT)AlignProp(cb);
pb += cbT - cb;
cb = cbT;
continue; // already updated, don't do it again
}
// Advance pointer and total count by the amount copied
cbT = AlignProp(cbT);
pb += cbT;
cb += cbT;
}
if (pcb)
{
Assert(!IsBadWritePtr(pcb, sizeof(ULONG)));
*pcb = cb;
}
return S_OK;
}
#ifdef NOTIFICATIONS
STDAPI_(SCODE)
ScRelocProps( int cprop,
LPSPropValue rgprop,
LPVOID pvBaseOld,
LPVOID pvBaseNew,
ULONG FAR *pcb)
{
LPSPropValue pprop;
ULONG cb;
UINT cbT;
LPVOID pvT;
int iValue;
BOOL fBaseNewValid = !IsBadReadPtr (pvBaseNew, sizeof (LPVOID));
// validate parameters
AssertSz(!cprop || !IsBadWritePtr(rgprop, sizeof(SPropValue) * cprop),
TEXT("rgprop fails address check"));
AssertSz(!pcb || !IsBadWritePtr(pcb, sizeof(ULONG)),
TEXT("pcb fails address check"));
// The old behavior of this code assumed that pvBaseNew was a usable
// pointer and that there would be no relocation to or from an unusable
// pointer. We've changed this so that you may relocate to or from an
// unusable pointer -- but logic to figure out whether to use the
// original or new pointer to fixup internal pointers was added.
// What we mean by this is that things like strlens and mv prop arrays
// need to be computed based on where the data ** CURRENTLY ** lives.
// The old rules allowed us to assume that the NEW location was always
// the right place. The new rules make us figure it out based on the
// validity of the two pointers pvBaseNew/Old, that are passed in.
//
// In order to preserve the old behavior, we try to use the new pointer
// (the one that was always used before) as the basis for internal
// pointer fixup. If it is bad (for example if we are relocating from
// something to zero), we will use the old pointer.
//
// A new wrinkle in the behavior of this code is a return of
// MAPI_E_INVALID_PARAMETER if both addresses appear invalid. This is
// to help protect this code for the mv or strlen case (though all
// other cases would have worked OK).
if (!fBaseNewValid && IsBadReadPtr (pvBaseOld, sizeof (LPVOID)))
{
DebugTrace ( TEXT("pvBaseOld and pvBaseNew failed address check"));
DebugTraceSc (ScRelocProps, MAPI_E_INVALID_PARAMETER);
return MAPI_E_INVALID_PARAMETER;
}
//$ SIZE Some of the multi-valued cases could be collapsed if we don't
//$ mind assuming that the counts and pointers are in the same place.
cb = cprop * sizeof(SPropValue);
for (pprop = rgprop; cprop--; ++pprop)
{
// Tricky: common code after the switch increments cb.
// If no increment is necessary, the case
// uses 'continue' rather than 'break' to exit the switch, thus
// skipping the increment -- AND any other code which may be
// added after the switch.
switch ( PROP_TYPE(pprop->ulPropTag) )
{
default:
DebugTrace( TEXT("ScRelocProps: Unknown property type %s")
TEXT(" (index %d)\n"),
SzDecodeUlPropTag(pprop->ulPropTag), pprop - rgprop);
return E_INVALIDARG;
case PT_I2:
case PT_LONG:
case PT_R4:
case PT_APPTIME:
case PT_DOUBLE:
case PT_BOOLEAN:
case PT_CURRENCY:
case PT_SYSTIME:
case PT_I8:
case PT_ERROR:
case PT_OBJECT:
case PT_NULL:
continue; // nothing to add or relocate
case PT_CLSID:
pprop->Value.lpguid = PvRelocPv(pprop->Value.lpguid,
pvBaseOld, pvBaseNew);
cbT = sizeof(GUID);
break;
case PT_BINARY:
pprop->Value.bin.lpb = PvRelocPv(pprop->Value.bin.lpb,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.bin.cb;
break;
case PT_STRING8:
// If we're assuming that the old pointer is OK (this
// means that we determined that the new one is not OK),
// save the current lpszA value in a temp variable. After
// the relocation, if the reverse is true, we'll put the
// relocated lpszA value into the temp variable.
//
// We then use the strlen of the string we hope the temp
// variable is pointing to, in order to compute the amount
// of space in the blob which is occupied by the string.
if (!fBaseNewValid)
pvT = pprop->Value.lpszA;
pprop->Value.lpszA = PvRelocPv(pprop->Value.lpszA,
pvBaseOld, pvBaseNew);
if (fBaseNewValid)
pvT = pprop->Value.lpszA;
cbT = lstrlenA((LPSTR)pvT) + 1;
break;
case PT_UNICODE:
// If we're assuming that the old pointer is OK (this
// means that we determined that the new one is not OK),
// save the current lpszW value in a temp variable. After
// the relocation, if the reverse is true, we'll put the
// relocated lpszW value into the temp variable.
//
// We then use the strlen of the string we hope the temp
// variable is pointing to, in order to compute the amount
// of space in the blob which is occupied by the string.
if (!fBaseNewValid)
pvT = pprop->Value.lpszW;
pprop->Value.lpszW = PvRelocPv(pprop->Value.lpszW,
pvBaseOld, pvBaseNew);
if (fBaseNewValid)
pvT = pprop->Value.lpszW;
cbT = (lstrlenW((LPWSTR)pvT) + 1) * sizeof(WCHAR);
break;
case PT_MV_I2:
pprop->Value.MVi.lpi = PvRelocPv(pprop->Value.MVi.lpi,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.MVi.cValues * sizeof(short int);
break;
case PT_MV_LONG:
pprop->Value.MVl.lpl = PvRelocPv(pprop->Value.MVl.lpl,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.MVl.cValues * sizeof(LONG);
break;
case PT_MV_R4:
pprop->Value.MVflt.lpflt = PvRelocPv(pprop->Value.MVflt.lpflt,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.MVflt.cValues * sizeof(float);
break;
case PT_MV_APPTIME:
pprop->Value.MVat.lpat = PvRelocPv(pprop->Value.MVat.lpat,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.MVat.cValues * sizeof(double);
break;
case PT_MV_DOUBLE:
pprop->Value.MVdbl.lpdbl = PvRelocPv(pprop->Value.MVdbl.lpdbl,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.MVdbl.cValues * sizeof(double);
break;
case PT_MV_CURRENCY:
pprop->Value.MVcur.lpcur = PvRelocPv(pprop->Value.MVcur.lpcur,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.MVcur.cValues * sizeof(CURRENCY);
break;
case PT_MV_SYSTIME:
pprop->Value.MVft.lpft = PvRelocPv(pprop->Value.MVft.lpft,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.MVft.cValues * sizeof(FILETIME);
break;
case PT_MV_CLSID:
pprop->Value.MVguid.lpguid = PvRelocPv(pprop->Value.MVguid.lpguid,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.MVguid.cValues * sizeof(GUID);
break;
case PT_MV_I8:
pprop->Value.MVli.lpli = PvRelocPv(pprop->Value.MVli.lpli,
pvBaseOld, pvBaseNew);
cbT = (UINT)pprop->Value.MVli.cValues * sizeof(LARGE_INTEGER);
break;
case PT_MV_BINARY:
{
LPSBinary lpsbT = pprop->Value.MVbin.lpbin;
pprop->Value.MVbin.lpbin = PvRelocPv(lpsbT, pvBaseOld, pvBaseNew);
// We've already set up a temporary variable to point to the
// pvBaseOld memory location. If pvBaseNew was OK, then we'll
// redirect the temp variable to the relocated memory before
// using it to correct the pointers in the MVbin array.
if (fBaseNewValid)
lpsbT = pprop->Value.MVbin.lpbin;
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVbin.cValues;
iValue++)
{
lpsbT[iValue].lpb = PvRelocPv(lpsbT[iValue].lpb, pvBaseOld, pvBaseNew);
cb += (UINT)AlignProp(lpsbT[iValue].cb);
}
continue; // already updated, don't do it again
}
case PT_MV_STRING8:
{
LPSTR * lppszT = pprop->Value.MVszA.lppszA;
pprop->Value.MVszA.lppszA = PvRelocPv(lppszT, pvBaseOld, pvBaseNew);
// We've already set up a temporary variable to point to the
// pvBaseOld memory location. If pvBaseNew was OK, then we'll
// redirect the temp variable to the relocated memory before
// using it to correct the pointers in the MVszA array.
if (fBaseNewValid)
lppszT = pprop->Value.MVszA.lppszA;
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVszA.cValues;
iValue++)
{
// If we're assuming that the old pointer is OK (this
// means that we determined that the new one is not OK),
// save the current lppszT value in a temp variable. After
// the relocation, if the reverse is true, we'll put the
// relocated lppszT value into the temp variable.
//
// We then use the strlen of the string we hope the temp
// variable is pointing to, in order to compute the amount
// of space in the blob which is occupied by the string.
if (!fBaseNewValid)
pvT = lppszT[iValue];
lppszT[iValue] = PvRelocPv(lppszT[iValue], pvBaseOld, pvBaseNew);
if (fBaseNewValid)
pvT = lppszT[iValue];
cb += lstrlenA((LPSTR)pvT) + 1;
}
cb = AlignProp(cb);
continue; // already updated, don't do it again
}
case PT_MV_UNICODE:
{
LPWSTR * lppszwT = pprop->Value.MVszW.lppszW;
pprop->Value.MVszW.lppszW = PvRelocPv(lppszwT, pvBaseOld, pvBaseNew);
// We've already set up a temporary variable to point to the
// pvBaseOld memory location. If pvBaseNew was OK, then we'll
// redirect the temp variable to the relocated memory before
// using it to correct the pointers in the MVszW array.
if (fBaseNewValid)
lppszwT = pprop->Value.MVszW.lppszW;
for (iValue = 0;
(ULONG)iValue < pprop->Value.MVszW.cValues;
iValue++)
{
// If we're assuming that the old pointer is OK (this
// means that we determined that the new one is not OK),
// save the current lppszwT value in a temp variable. After
// the relocation, if the reverse is true, we'll put the
// relocated lppszwT value into the temp variable.
//
// We then use the strlen of the string we hope the temp
// variable is pointing to, in order to compute the amount
// of space in the blob which is occupied by the string.
if (!fBaseNewValid)
pvT = lppszwT[iValue];
lppszwT[iValue] = PvRelocPv(lppszwT[iValue], pvBaseOld, pvBaseNew);
if (fBaseNewValid)
pvT = lppszwT[iValue];
cb += (lstrlenW(lppszwT[iValue]) + 1) * sizeof(WCHAR);
}
cb = AlignProp(cb);
continue; // already updated, don't do it again
}
}
// Advance total count
cb += AlignProp(cbT);
}
if (pcb)
{
Assert(!IsBadWritePtr(pcb, sizeof(ULONG)));
*pcb = cb;
}
return S_OK;
}
#endif
/*
* Wrapper function to just duplicate a property value array
* into a single block of MAPI memory.
*/
STDAPI_(SCODE)
ScDupPropset(int cprop, LPSPropValue rgprop, LPALLOCATEBUFFER palloc,
LPSPropValue FAR *prgprop)
{
ULONG cb;
SCODE sc;
// validate parameters
AssertSz(!cprop || !IsBadReadPtr(rgprop, sizeof(SPropValue) * cprop),
TEXT("rgprop fails address check"));
AssertSz(!IsBadCodePtr((FARPROC)palloc), TEXT("palloc fails address check"));
AssertSz(!IsBadWritePtr(prgprop, sizeof(LPSPropValue)),
TEXT("prgprop fails address check"));
// Find out how much memory we need
if (sc = ScCountProps(cprop, rgprop, &cb))
goto ret;
// Obtain memory
if (sc = (*palloc)(cb, (LPVOID *)prgprop))
goto ret;
// Copy the properties
if (sc = ScCopyProps(cprop, rgprop, *prgprop, &cb))
goto ret;
ret:
DebugTraceSc(ScDupPropset, sc);
return sc;
}