/* * 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; }