|
|
/*
* MAPI 1.0 property handling routines * * * PROPUTIL.C - * * Useful routines for manipulating and comparing property values */
#include <_apipch.h>
//
//
// WARNING! WARNING! WARNING! 32-bit Intel Specific!
//
//
#define SIZEOF_FLOAT 4
#define SIZEOF_DOUBLE 8
#define SIZEOF_LONG_DOUBLE 8
// Make linker happy.
BOOL _fltused; //
//
//
//
#define cchBufMax 256
#if defined (_AMD64_) || defined(_IA64_)
#define AlignProp(_cb) Align8(_cb)
#else
#define AlignProp(_cb) (_cb)
#endif
#ifdef OLD_STUFF
//#ifdef OLDSTUFF_DBCS
ULONG ulchStrCount (LPTSTR, ULONG, LANGID); ULONG ulcbStrCount (LPTSTR, ULONG, LANGID); //#endif // DBCS
#endif //OLD_STUFF
// $MAC - Mac 68K compiler bug
#ifdef _M_M68K
#pragma optimize( TEXT(""), off)
#endif
/*
- PropCopyMore() - * * Copies a property pointed to by lpSPropValueSrc into the property pointed * to by lpSPropValueDst. No memory allocation is done unless the property * is one of the types that do not fit within a SPropValue, eg. STRING8 * For these large properties, memory is allocated using * the AllocMore function passed as a parameter. */
STDAPI_(SCODE) PropCopyMore( LPSPropValue lpSPropValueDst, LPSPropValue lpSPropValueSrc, ALLOCATEMORE * lpfAllocateMore, LPVOID lpvObject ) { SCODE sc; ULONG ulcbValue; LPBYTE lpbValueSrc; UNALIGNED LPBYTE * lppbValueDst;
// validate parameters
AssertSz( lpSPropValueDst && !IsBadReadPtr( lpSPropValueDst, sizeof( SPropValue ) ), TEXT("lpSPropValueDst fails address check") );
AssertSz( lpSPropValueSrc && !IsBadReadPtr( lpSPropValueSrc, sizeof( SPropValue ) ), TEXT("lpSPropValueDst fails address check") );
AssertSz( !lpfAllocateMore || !IsBadCodePtr( (FARPROC)lpfAllocateMore ), TEXT("lpfAllocateMore fails address check") );
AssertSz( !lpvObject || !IsBadReadPtr( lpvObject, sizeof( LPVOID ) ), TEXT("lpfAllocateMore fails address check") );
// Copy the part that fits in the SPropValue struct (including the tag).
// This is a little wasteful for complicated properties
// because it copies more than is strictly necessary, but
// it saves time for small properties and saves code in general
MemCopy( (BYTE *) lpSPropValueDst, (BYTE *) lpSPropValueSrc, sizeof(SPropValue) );
switch ( PROP_TYPE(lpSPropValueSrc->ulPropTag) ) { // Types whose values fit in the 64-bit Value of the property
// or whose values aren't anything PropCopyMore can interpret
case PT_UNSPECIFIED: case PT_NULL: case PT_OBJECT: case PT_I2: case PT_LONG: case PT_R4: case PT_DOUBLE: case PT_CURRENCY: case PT_ERROR: case PT_BOOLEAN: case PT_SYSTIME: case PT_APPTIME: case PT_I8:
return SUCCESS_SUCCESS;
case PT_BINARY:
ulcbValue = lpSPropValueSrc->Value.bin.cb; lpbValueSrc = lpSPropValueSrc->Value.bin.lpb; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.bin.lpb;
break;
case PT_STRING8:
ulcbValue = (lstrlenA(lpSPropValueSrc->Value.lpszA) + 1) * sizeof(CHAR); lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.lpszA; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.lpszA;
break;
case PT_UNICODE:
ulcbValue = (lstrlenW(lpSPropValueSrc->Value.lpszW) + 1) * sizeof(WCHAR); lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.lpszW; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.lpszW;
break;
case PT_CLSID:
ulcbValue = sizeof(GUID); lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.lpguid; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.lpguid;
break;
case PT_MV_CLSID:
ulcbValue = lpSPropValueSrc->Value.MVguid.cValues * sizeof(GUID); lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVguid.lpguid; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVguid.lpguid;
break;
case PT_MV_I2:
ulcbValue = lpSPropValueSrc->Value.MVi.cValues * sizeof(short int); lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVi.lpi; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVi.lpi;
break;
case PT_MV_LONG:
ulcbValue = lpSPropValueSrc->Value.MVl.cValues * sizeof(LONG); lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVl.lpl; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVl.lpl;
break;
case PT_MV_R4:
ulcbValue = lpSPropValueSrc->Value.MVflt.cValues * SIZEOF_FLOAT; lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVflt.lpflt; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVflt.lpflt;
break;
case PT_MV_DOUBLE: case PT_MV_APPTIME:
ulcbValue = lpSPropValueSrc->Value.MVdbl.cValues * SIZEOF_DOUBLE; lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVdbl.lpdbl; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVdbl.lpdbl;
break;
case PT_MV_CURRENCY:
ulcbValue = lpSPropValueSrc->Value.MVcur.cValues * sizeof(CURRENCY); lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVcur.lpcur; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVcur.lpcur;
break;
case PT_MV_SYSTIME:
ulcbValue = lpSPropValueSrc->Value.MVat.cValues * sizeof(FILETIME); lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVat.lpat; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVat.lpat;
break;
case PT_MV_I8:
ulcbValue = lpSPropValueSrc->Value.MVli.cValues * sizeof(LARGE_INTEGER); lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVli.lpli; lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVli.lpli;
break;
case PT_MV_BINARY: { // Multi-valued binaries are copied in memory into a single
// allocated buffer in the following way:
//
// cb1, pb1 ... cbn, pbn, b1,0, b1,1 ... b2,0 b2,1 ...
//
// The cbn and pbn parameters form the SBinary array that
// will be pointed to by lpSPropValueDst->Value.MVbin.lpbin.
// The remainder of the allocation is used to store the binary
// data for each of the elements of the array. Thus pb1 points
// to the b1,0, etc.
UNALIGNED SBinaryArray * pSBinaryArray = (UNALIGNED SBinaryArray * ) (&lpSPropValueSrc->Value.MVbin); ULONG uliValue; UNALIGNED SBinary * pSBinarySrc; UNALIGNED SBinary * pSBinaryDst; LPBYTE pbData;
ulcbValue = pSBinaryArray->cValues * sizeof(SBinary);
for ( uliValue = 0, pSBinarySrc = pSBinaryArray->lpbin; uliValue < pSBinaryArray->cValues; uliValue++, pSBinarySrc++ )
ulcbValue += AlignProp(pSBinarySrc->cb);
// Allocate a buffer to hold it all
lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVbin.lpbin;
sc = (*lpfAllocateMore)( ulcbValue, lpvObject, (LPVOID *) lppbValueDst );
if ( sc != SUCCESS_SUCCESS ) { DebugTrace( TEXT("PropCopyMore() - OOM allocating space for dst PT_MV_BINARY property") ); return sc; }
// And copy it all in
pbData = (LPBYTE) ((LPSBinary) *lppbValueDst + pSBinaryArray->cValues);
for ( uliValue = 0, pSBinarySrc = pSBinaryArray->lpbin, pSBinaryDst = (LPSBinary) *lppbValueDst;
uliValue < pSBinaryArray->cValues;
uliValue++, pSBinarySrc++, pSBinaryDst++ ) { pSBinaryDst->cb = pSBinarySrc->cb; pSBinaryDst->lpb = pbData; MemCopy( pbData, pSBinarySrc->lpb, (UINT) pSBinarySrc->cb ); pbData += AlignProp(pSBinarySrc->cb); }
return SUCCESS_SUCCESS; }
case PT_MV_STRING8: { // Multi-valued STRING8 properties are copied into a single
// allocated block of memory in the following way:
//
// | Allocated buffer |
// |---------------------------------------|
// | pszA1, pszA2 ... | szA1[], szA2[] ... |
// |------------------|--------------------|
// | LPSTR array | String data |
//
// Where pszAn are the elements of the LPSTR array pointed
// to by lpSPropValueDst->Value.MVszA. Each pszAn points
// to its corresponding string, szAn, stored later in the
// buffer. The szAn are stored starting at the first byte
// past the end of the LPSTR array.
UNALIGNED SLPSTRArray * pSLPSTRArray = (UNALIGNED SLPSTRArray *) (&lpSPropValueSrc->Value.MVszA); ULONG uliValue; LPSTR * pszASrc; LPSTR * pszADst; LPBYTE pbSzA; ULONG ulcbSzA;
// Figure out the size of the buffer we need
ulcbValue = pSLPSTRArray->cValues * sizeof(LPSTR);
for ( uliValue = 0, pszASrc = pSLPSTRArray->lppszA; uliValue < pSLPSTRArray->cValues; uliValue++, pszASrc++ )
ulcbValue += (lstrlenA(*pszASrc) + 1) * sizeof(CHAR);
// Allocate the buffer to hold the strings
lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVszA.lppszA;
sc = (*lpfAllocateMore)( ulcbValue, lpvObject, (LPVOID *) lppbValueDst );
if ( sc != SUCCESS_SUCCESS ) { DebugTrace( TEXT("PropCopyMore() - OOM allocating space for dst PT_MV_STRING8 property") ); return sc; }
// Copy the strings into the buffer and set pointers
// to them in the LPSTR array at the beginning of the buffer
for ( uliValue = 0, pszASrc = pSLPSTRArray->lppszA, pszADst = (LPSTR *) *lppbValueDst, pbSzA = (LPBYTE) (pszADst + pSLPSTRArray->cValues);
uliValue < pSLPSTRArray->cValues;
uliValue++, pszASrc++, pszADst++ ) { ulcbSzA = (lstrlenA(*pszASrc) + 1) * sizeof(CHAR);
*pszADst = (LPSTR) pbSzA; MemCopy( pbSzA, (LPBYTE) *pszASrc, (UINT) ulcbSzA ); pbSzA += ulcbSzA; }
return SUCCESS_SUCCESS; }
case PT_MV_UNICODE: { // Multi-valued UNICODE properties are copied into a single
// allocated block of memory in the following way:
//
// | Allocated buffer |
// |---------------------------------------|
// | pszW1, pszW2 ... | szW1[], szW2[] ... |
// |------------------|--------------------|
// | LPWSTR array | String data |
//
// Where pszWn are the elements of the LPWSTR array pointed
// to by lpSPropValueDst->Value.MVszW. Each pszWn points
// to its corresponding string, szWn, stored later in the
// buffer. The szWn are stored starting at the first byte
// past the end of the LPWSTR array.
UNALIGNED SWStringArray * pSWStringArray = (UNALIGNED SWStringArray *) (&lpSPropValueSrc->Value.MVszW); ULONG uliValue; UNALIGNED LPWSTR * pszWSrc; UNALIGNED LPWSTR * pszWDst; LPBYTE pbSzW; ULONG ulcbSzW;
// Figure out the size of the buffer we need
ulcbValue = pSWStringArray->cValues * sizeof(LPWSTR);
for ( uliValue = 0, pszWSrc = pSWStringArray->lppszW; uliValue < pSWStringArray->cValues; uliValue++, pszWSrc++ )
ulcbValue += (lstrlenW(*pszWSrc) + 1) * sizeof(WCHAR);
// Allocate the buffer to hold the strings
lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVszW.lppszW;
sc = (*lpfAllocateMore)( ulcbValue, lpvObject, (LPVOID *) lppbValueDst );
if ( sc != SUCCESS_SUCCESS ) { DebugTrace( TEXT("PropCopyMore() - OOM allocating space for dst PT_MV_UNICODE property") ); return sc; }
// Copy the strings into the buffer and set pointers
// to them in the LPWSTR array at the beginning of the buffer
for ( uliValue = 0, pszWSrc = pSWStringArray->lppszW, pszWDst = (LPWSTR *) *lppbValueDst, pbSzW = (LPBYTE) (pszWDst + pSWStringArray->cValues);
uliValue < pSWStringArray->cValues;
uliValue++, pszWSrc++, pszWDst++ ) { ulcbSzW = (lstrlenW(*pszWSrc) + 1) * sizeof(WCHAR);
*((UNALIGNED LPWSTR *) pszWDst) = (LPWSTR) pbSzW; Assert(ulcbSzW < 0xFfff); MemCopy( pbSzW, (LPBYTE) *pszWSrc, (UINT) ulcbSzW ); pbSzW += ulcbSzW; }
return SUCCESS_SUCCESS; }
default:
DebugTrace( TEXT("PropCopyMore() - Unsupported/Unimplemented property type 0x%04x"), PROP_TYPE(lpSPropValueSrc->ulPropTag) ); return MAPI_E_NO_SUPPORT; }
sc = (*lpfAllocateMore)( ulcbValue, lpvObject, (LPVOID *) lppbValueDst );
if ( sc != SUCCESS_SUCCESS ) { DebugTrace( TEXT("PropCopyMore() - OOM allocating space for dst property") ); return sc; }
MemCopy( *lppbValueDst, lpbValueSrc, (UINT) ulcbValue );
return SUCCESS_SUCCESS; }
// $MAC - Mac 68K compiler bug
#ifdef _M_M68K
#pragma optimize( TEXT(""), on)
#endif
/*
- UlPropSize() * * Returns the size of the property pointed to by lpSPropValue */
STDAPI_(ULONG) UlPropSize( LPSPropValue lpSPropValue ) { // parameter validation
AssertSz( lpSPropValue && !IsBadReadPtr( lpSPropValue, sizeof( SPropValue ) ), TEXT("lpSPropValue fails address check") );
switch ( PROP_TYPE(lpSPropValue->ulPropTag) ) { case PT_I2: return sizeof(short int); case PT_LONG: return sizeof(LONG); case PT_R4: return SIZEOF_FLOAT; case PT_APPTIME: case PT_DOUBLE: return SIZEOF_DOUBLE; case PT_BOOLEAN: return sizeof(unsigned short int); case PT_CURRENCY: return sizeof(CURRENCY); case PT_SYSTIME: return sizeof(FILETIME); case PT_CLSID: return sizeof(GUID); case PT_I8: return sizeof(LARGE_INTEGER); case PT_ERROR: return sizeof(SCODE); case PT_BINARY: return lpSPropValue->Value.bin.cb; case PT_STRING8: return (lstrlenA( lpSPropValue->Value.lpszA ) + 1) * sizeof(CHAR); case PT_UNICODE: return (lstrlenW( lpSPropValue->Value.lpszW ) + 1) * sizeof(WCHAR);
case PT_MV_I2: return lpSPropValue->Value.MVi.cValues * sizeof(short int); case PT_MV_LONG: return lpSPropValue->Value.MVl.cValues * sizeof(LONG); case PT_MV_R4: return lpSPropValue->Value.MVflt.cValues * SIZEOF_FLOAT; case PT_MV_APPTIME: case PT_MV_DOUBLE: return lpSPropValue->Value.MVdbl.cValues * SIZEOF_DOUBLE; case PT_MV_CURRENCY: return lpSPropValue->Value.MVcur.cValues * sizeof(CURRENCY); case PT_MV_SYSTIME: return lpSPropValue->Value.MVat.cValues * sizeof(FILETIME); case PT_MV_I8: return lpSPropValue->Value.MVli.cValues * sizeof(LARGE_INTEGER);
case PT_MV_BINARY: { ULONG ulcbSize = 0; ULONG uliValue;
for ( uliValue = 0; uliValue < lpSPropValue->Value.MVbin.cValues; uliValue++ )
ulcbSize += AlignProp((lpSPropValue->Value.MVbin.lpbin + uliValue)->cb);
return ulcbSize; }
case PT_MV_STRING8: { ULONG ulcbSize = 0; ULONG uliValue;
for ( uliValue = 0; uliValue < lpSPropValue->Value.MVszA.cValues; uliValue++ )
ulcbSize += (lstrlenA(*(lpSPropValue->Value.MVszA.lppszA + uliValue)) + 1) * sizeof(CHAR);
return ulcbSize; }
case PT_MV_UNICODE: { ULONG ulcbSize = 0; ULONG uliValue;
for ( uliValue = 0; uliValue < lpSPropValue->Value.MVszW.cValues; uliValue++ )
ulcbSize += (lstrlenW(*(lpSPropValue->Value.MVszW.lppszW + uliValue)) + 1) * sizeof(WCHAR);
return ulcbSize; } }
return 0; }
/**************************************************************************
* GetInstance * * Purpose * Fill in an SPropValue with an instance of an MV propvalue * * Parameters * pvalMv The Mv property * pvalSv The Sv propery to fill * uliInst The instance with which to fill pvalSv */ STDAPI_(void) GetInstance(LPSPropValue pvalMv, LPSPropValue pvalSv, ULONG uliInst) { switch (PROP_TYPE(pvalSv->ulPropTag)) { case PT_I2: pvalSv->Value.li = pvalMv->Value.MVli.lpli[uliInst]; break; case PT_LONG: pvalSv->Value.l = pvalMv->Value.MVl.lpl[uliInst]; break; case PT_R4: pvalSv->Value.flt = pvalMv->Value.MVflt.lpflt[uliInst]; break; case PT_DOUBLE: pvalSv->Value.dbl = pvalMv->Value.MVdbl.lpdbl[uliInst]; break; case PT_CURRENCY: pvalSv->Value.cur = pvalMv->Value.MVcur.lpcur[uliInst]; break; case PT_APPTIME : pvalSv->Value.at = pvalMv->Value.MVat.lpat[uliInst]; break; case PT_SYSTIME: pvalSv->Value.ft = pvalMv->Value.MVft.lpft[uliInst]; break; case PT_STRING8: pvalSv->Value.lpszA = pvalMv->Value.MVszA.lppszA[uliInst]; break; case PT_BINARY: pvalSv->Value.bin = pvalMv->Value.MVbin.lpbin[uliInst]; break; case PT_UNICODE: pvalSv->Value.lpszW = pvalMv->Value.MVszW.lppszW[uliInst]; break; case PT_CLSID: pvalSv->Value.lpguid = &pvalMv->Value.MVguid.lpguid[uliInst]; break; default: DebugTrace( TEXT("GetInstance() - Unsupported/unimplemented property type 0x%08lx"), PROP_TYPE(pvalMv->ulPropTag) ); pvalSv->ulPropTag = PT_NULL; return; } }
LPTSTR PszNormalizePsz(LPTSTR pszIn, BOOL fExact) { LPTSTR pszOut = NULL; UINT cb = 0;
if (fExact) return pszIn;
cb = sizeof(CHAR) * (lstrlen(pszIn) + 1);
if (FAILED(MAPIAllocateBuffer(cb, (LPVOID *)&pszOut))) return NULL;
MemCopy(pszOut, pszIn, cb);
#if defined(WIN16) || defined(WIN32)
CharUpper(pszOut); #else
//$TODO: This should be inlined in the mapinls.h for non WIN
//$ but I didn't want to do all the cases of CharUpper.
//$DRM What about other languages?
{ CHAR *pch;
for (pch = pszOut; *pch; pch++) { if (*pch >= 'a' && *pch <= 'z') *pch = (CHAR)(*pch - 'a' + 'A'); } } #endif
return pszOut; }
#ifdef TABLES
/*
- FPropContainsProp() - * Compares two properties to see if one TEXT("contains") the other * according to a fuzzy level heuristic. * * The method of comparison depends on the type of the properties * being compared and the fuzzy level: * * Property types Fuzzy Level Comparison * -------------- ----------- ---------- * PT_STRING8 FL_FULLSTRING Returns TRUE if the value of the source * PT_BINARY and target string are equivalent. With * no other flags is equivalent to * RES_PROPERTY with RELOP_EQ * returns FALSE otherwise. * * PT_STRING8 FL_SUBSTRING Returns TRUE if Pattern is contained * PT_BINARY as a substring in Target * returns FALSE otherwise. * * PT_STRING8 FL_IGNORECASE All comparisons are done case insensitively * * PT_STRING8 FL_IGNORENONSPACE THIS IS NOT (YET?) IMPLEMENTED * All comparisons ignore what in unicode are * called TEXT("non-spacing characters") such as * diacritics. * * PT_STRING8 FL_LOOSE Provider adds value by doing as much of * FL_IGNORECASE and FL_IGNORESPACE as he wants * * PT_STRING8 FL_PREFIX Pattern and Target are compared only up to * PT_BINARY the length of Pattern * * PT_STRING8 any other Ignored * * * PT_BINARY any not defined Returns TRUE if the value of the property * above pointed to by lpSPropValueTarget contains the * sequence of bytes which is the value of * the property pointed to by lpSPropValuePattern; * returns FALSE otherwise. * * Error returns: * * FALSE If the properties being compared are not both of the same * type, or if one or both of those properties is not one * of the types listed above, or if the fuzzy level is not * one of those listed above. */
STDAPI_(BOOL) FPropContainsProp( LPSPropValue lpSPropValueTarget, LPSPropValue lpSPropValuePattern, ULONG ulFuzzyLevel ) { SPropValue sval; ULONG uliInst; LCID lcid = GetUserDefaultLCID(); DWORD dwCSFlags = ((!(ulFuzzyLevel & FL_IGNORECASE)-1) & (NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH)) | ((!(ulFuzzyLevel & FL_IGNORENONSPACE)-1) & NORM_IGNORENONSPACE);
// Validate parameters
AssertSz( lpSPropValueTarget && !IsBadReadPtr( lpSPropValueTarget, sizeof( SPropValue ) ), TEXT("lpSPropValueTarget fails address check") );
AssertSz( lpSPropValuePattern && !IsBadReadPtr( lpSPropValuePattern, sizeof( SPropValue ) ), TEXT("lpSPropValuePattern fails address check") );
if (ulFuzzyLevel & FL_LOOSE) dwCSFlags |= NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH;
if ( !(lpSPropValuePattern->ulPropTag & MV_FLAG) && lpSPropValueTarget->ulPropTag & MV_FLAG) { sval.ulPropTag = lpSPropValueTarget->ulPropTag & ~MV_FLAG; uliInst = lpSPropValueTarget->Value.MVbin.cValues; while (uliInst-- > 0) { GetInstance(lpSPropValueTarget, &sval, uliInst); if (FPropContainsProp(&sval, lpSPropValuePattern, ulFuzzyLevel)) return TRUE; } return FALSE; }
if ( PROP_TYPE(lpSPropValuePattern->ulPropTag) != PROP_TYPE(lpSPropValueTarget->ulPropTag) ) return FALSE;
switch ( PROP_TYPE(lpSPropValuePattern->ulPropTag) ) { case PT_STRING8: // [PaulHi] 2/16/99 single byte string version
if (ulFuzzyLevel & FL_SUBSTRING) { return FRKFindSubpsz(lpSPropValueTarget->Value.lpszA, lstrlenA(lpSPropValueTarget->Value.lpszA), lpSPropValuePattern->Value.lpszA, lstrlenA(lpSPropValuePattern->Value.lpszA), ulFuzzyLevel); } else // FL_PREFIX or FL_FULLSTRING
{ UINT cch;
if (ulFuzzyLevel & FL_PREFIX) { cch = (UINT)lstrlenA(lpSPropValuePattern->Value.lpszA);
if (cch > (UINT)lstrlenA(lpSPropValueTarget->Value.lpszA)) return(FALSE); } else cch = (UINT)-1;
return CompareStringA(lcid, dwCSFlags, lpSPropValueTarget->Value.lpszA, cch, lpSPropValuePattern->Value.lpszA, cch) == 2; }
case PT_UNICODE: // [PaulHi] 2/16/99 double byte string version
if (ulFuzzyLevel & FL_SUBSTRING) { LPSTR lpszTarget = ConvertWtoA(lpSPropValueTarget->Value.lpszW); LPSTR lpszPattern = ConvertWtoA(lpSPropValuePattern->Value.lpszW); BOOL bRtn = FALSE;
if (lpszTarget && lpszPattern) { bRtn = FRKFindSubpsz(lpszTarget, lstrlenA(lpszTarget), lpszPattern, lstrlenA(lpszPattern), ulFuzzyLevel); } LocalFreeAndNull(&lpszTarget); LocalFreeAndNull(&lpszPattern);
return bRtn; } else // FL_PREFIX or FL_FULLSTRING
{ UINT cch;
if (ulFuzzyLevel & FL_PREFIX) { cch = (UINT)lstrlen(lpSPropValuePattern->Value.lpszW);
if (cch > (UINT)lstrlen(lpSPropValueTarget->Value.lpszW)) return(FALSE); } else cch = (UINT)-1;
return CompareString(lcid, dwCSFlags, lpSPropValueTarget->Value.lpszW, cch, lpSPropValuePattern->Value.lpszW, cch) == 2; } break;
case PT_BINARY: if (ulFuzzyLevel & FL_SUBSTRING) return FRKFindSubpb(lpSPropValueTarget->Value.bin.lpb, lpSPropValueTarget->Value.bin.cb, lpSPropValuePattern->Value.bin.lpb, lpSPropValuePattern->Value.bin.cb); else if (ulFuzzyLevel & FL_PREFIX) { if (lpSPropValuePattern->Value.bin.cb > lpSPropValueTarget->Value.bin.cb) return FALSE; } else // FL_FULLSTRING
if (lpSPropValuePattern->Value.bin.cb != lpSPropValueTarget->Value.bin.cb) return FALSE;
return !memcmp(lpSPropValuePattern->Value.bin.lpb, lpSPropValueTarget->Value.bin.lpb, (UINT) lpSPropValuePattern->Value.bin.cb);
case PT_MV_STRING8: { SPropValue spvT, spvP; ULONG i;
// [PaulHi] 2/16/99 single byte string version
// To do MV_STRING we will break up the individual strings in the target
// into single STRING prop values and pass them recursively back into this
// function.
// We expect the pattern MV prop to contain exactly one string. It's kind
// of hard to decide what the behavior should be otherwise.
if (lpSPropValuePattern->Value.MVszA.cValues != 1) { DebugTrace( TEXT("FPropContainsProp() - PT_MV_STRING8 of pattern must have cValues == 1\n")); return(FALSE); }
// Turn off the MV flag and pass in each string seperately
spvP.ulPropTag = spvT.ulPropTag = lpSPropValuePattern->ulPropTag & ~MV_FLAG; spvP.Value.lpszA = *lpSPropValuePattern->Value.MVszA.lppszA;
for (i = 0; i < lpSPropValueTarget->Value.MVszA.cValues; i++) { spvT.Value.lpszA = lpSPropValueTarget->Value.MVszA.lppszA[i]; if (FPropContainsProp(&spvT, &spvP, ulFuzzyLevel)) { return(TRUE); } } return(FALSE); } break;
case PT_MV_UNICODE: { SPropValue spvT, spvP; ULONG i;
// [PaulHi] 2/16/99 double byte string version
// To do MV_STRING we will break up the individual strings in the target
// into single STRING prop values and pass them recursively back into this
// function.
// We expect the pattern MV prop to contain exactly one string. It's kind
// of hard to decide what the behavior should be otherwise.
if (lpSPropValuePattern->Value.MVszW.cValues != 1) { DebugTrace( TEXT("FPropContainsProp() - PT_MV_UNICODE of pattern must have cValues == 1\n")); return(FALSE); }
// Turn off the MV flag and pass in each string seperately
spvP.ulPropTag = spvT.ulPropTag = lpSPropValuePattern->ulPropTag & ~MV_FLAG; spvP.Value.lpszW = *lpSPropValuePattern->Value.MVszW.lppszW;
for (i = 0; i < lpSPropValueTarget->Value.MVszW.cValues; i++) { spvT.Value.lpszW = lpSPropValueTarget->Value.MVszW.lppszW[i]; if (FPropContainsProp(&spvT, &spvP, ulFuzzyLevel)) { return(TRUE); } } return(FALSE); } break;
default: DebugTrace( TEXT("FPropContainsProp() - Unsupported/unimplemented property type 0x%08lx\n"), PROP_TYPE(lpSPropValuePattern->ulPropTag) ); return FALSE; } // end switch(ulPropTag)
}
/*
- FPropCompareProp() - * Compares the property pointed to by lpSPropValue1 with the property * pointed to by lpSPropValue2 using the binary relational operator * specified by ulRelOp. The order of comparison is: * * Property1 Operator Property2 */
STDAPI_(BOOL) FPropCompareProp( LPSPropValue lpSPropValue1, ULONG ulRelOp, LPSPropValue lpSPropValue2 ) { SPropValue sval; ULONG uliInst;
// Validate parameters
AssertSz( lpSPropValue1 && !IsBadReadPtr( lpSPropValue1, sizeof( SPropValue ) ), TEXT("lpSPropValue1 fails address check") );
AssertSz( lpSPropValue2 && !IsBadReadPtr( lpSPropValue2, sizeof( SPropValue ) ), TEXT("lpSPropValue2 fails address check") );
if ( !(lpSPropValue2->ulPropTag & MV_FLAG) && lpSPropValue1->ulPropTag & MV_FLAG) { sval.ulPropTag = lpSPropValue1->ulPropTag & ~MV_FLAG; uliInst = lpSPropValue1->Value.MVbin.cValues; while (uliInst-- > 0) { GetInstance(lpSPropValue1, &sval, uliInst); if (FPropCompareProp(&sval, ulRelOp, lpSPropValue2)) return TRUE; } return FALSE; }
// If the prop types don't match then the properties are not
// equal but otherwise uncomparable
//
if (PROP_TYPE(lpSPropValue1->ulPropTag) != PROP_TYPE(lpSPropValue2->ulPropTag))
return (ulRelOp == RELOP_NE);
switch ( ulRelOp ) { case RELOP_LT:
return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) < 0;
case RELOP_LE:
return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) <= 0;
case RELOP_GT:
return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) > 0;
case RELOP_GE:
return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) >= 0;
case RELOP_EQ:
return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) == 0;
case RELOP_NE:
return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) != 0;
case RELOP_RE:
return FALSE; }
DebugTrace( TEXT("FPropCompareProp() - Unknown relop 0x%08lx"), ulRelOp ); return FALSE; }
/*
- LPropCompareProp() - * Description: * * Compares two properties to determine the ordering * relation between the two. For property types which * have no intrinsic ordering (eg. BOOLEAN, ERROR, etc.) * this function simply determines if the two are equal * or not equal. If they are not equal, the returned * value is not defined, but it will be non-zero and * will be consistent across calls. * * * Returns: * * < 0 if property A is TEXT("less than") property B * > 0 if property A is TEXT("greater than") property B * 0 if property A TEXT("equals") property B * */
STDAPI_(LONG) LPropCompareProp( LPSPropValue lpSPropValueA, LPSPropValue lpSPropValueB ) { ULONG uliinst; ULONG ulcinst; LONG lRetval; LCID lcid = GetUserDefaultLCID();
// Validate parameters
AssertSz( lpSPropValueA && !IsBadReadPtr( lpSPropValueA, sizeof( SPropValue ) ), TEXT("lpSPropValueA fails address check") );
AssertSz( lpSPropValueB && !IsBadReadPtr( lpSPropValueB, sizeof( SPropValue ) ), TEXT("lpSPropValueB fails address check") );
Assert( PROP_TYPE(lpSPropValueA->ulPropTag) == PROP_TYPE(lpSPropValueB->ulPropTag) );
if (lpSPropValueA->ulPropTag & MV_FLAG) { ulcinst = min(lpSPropValueA->Value.MVi.cValues, lpSPropValueB->Value.MVi.cValues); for (uliinst = 0; uliinst < ulcinst; uliinst++) { switch (PROP_TYPE(lpSPropValueA->ulPropTag)) { case PT_MV_I2:
if (lRetval = lpSPropValueA->Value.MVi.lpi[uliinst] - lpSPropValueB->Value.MVi.lpi[uliinst]) return lRetval; break;
case PT_MV_LONG:
if (lRetval = lpSPropValueA->Value.MVl.lpl[uliinst] - lpSPropValueB->Value.MVl.lpl[uliinst]) return lRetval; break;
case PT_MV_R4:
if (lpSPropValueA->Value.MVflt.lpflt[uliinst] != lpSPropValueB->Value.MVflt.lpflt[uliinst]) return lpSPropValueA->Value.MVflt.lpflt[uliinst] < lpSPropValueB->Value.MVflt.lpflt[uliinst] ? -1 : 1; break;
case PT_MV_DOUBLE:
if (lpSPropValueA->Value.MVdbl.lpdbl[uliinst] != lpSPropValueB->Value.MVdbl.lpdbl[uliinst]) return lpSPropValueA->Value.MVdbl.lpdbl[uliinst] < lpSPropValueB->Value.MVdbl.lpdbl[uliinst] ? -1 : 1; break;
case PT_MV_SYSTIME:
lRetval = lpSPropValueA->Value.MVft.lpft[uliinst].dwHighDateTime == lpSPropValueB->Value.MVft.lpft[uliinst].dwHighDateTime ? (lpSPropValueA->Value.MVft.lpft[uliinst].dwLowDateTime != lpSPropValueB->Value.MVft.lpft[uliinst].dwLowDateTime ? (lpSPropValueA->Value.MVft.lpft[uliinst].dwLowDateTime < lpSPropValueB->Value.MVft.lpft[uliinst].dwLowDateTime ? -1 : 1) : 0) : (lpSPropValueA->Value.MVft.lpft[uliinst].dwHighDateTime < lpSPropValueB->Value.MVft.lpft[uliinst].dwHighDateTime ? -1 : 1);
if (lRetval) return lRetval; break;
case PT_MV_BINARY:
lRetval = lpSPropValueA->Value.MVbin.lpbin[uliinst].cb != lpSPropValueB->Value.MVbin.lpbin[uliinst].cb ? (lpSPropValueA->Value.MVbin.lpbin[uliinst].cb < lpSPropValueB->Value.MVbin.lpbin[uliinst].cb ? -1 : 1) : memcmp(lpSPropValueA->Value.MVbin.lpbin[uliinst].lpb, lpSPropValueB->Value.MVbin.lpbin[uliinst].lpb, (UINT) lpSPropValueA->Value.MVbin.lpbin[uliinst].cb);
if (lRetval) return lRetval; break;
case PT_MV_STRING8:
lRetval = CompareStringA(lcid, NORM_IGNORECASE | NORM_IGNORENONSPACE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH, lpSPropValueA->Value.MVszA.lppszA[uliinst], -1, lpSPropValueB->Value.MVszA.lppszA[uliinst], -1) - 2;
if (lRetval) return lRetval; break;
case PT_MV_UNICODE:
lRetval = CompareStringW(lcid, NORM_IGNORECASE | NORM_IGNORENONSPACE | NORM_IGNOREKANATYPE, lpSPropValueA->Value.MVszW.lppszW[uliinst], -1, lpSPropValueB->Value.MVszW.lppszW[uliinst], -1) - 2;
if (lRetval) return lRetval; break;
case PT_MV_I8: case PT_MV_CURRENCY:
lRetval = lpSPropValueA->Value.MVli.lpli[uliinst].HighPart == lpSPropValueB->Value.MVli.lpli[uliinst].HighPart ? (lpSPropValueA->Value.MVli.lpli[uliinst].LowPart != lpSPropValueB->Value.MVli.lpli[uliinst].LowPart ? (lpSPropValueA->Value.MVli.lpli[uliinst].LowPart < lpSPropValueB->Value.MVli.lpli[uliinst].LowPart ? -1 : 1) : 0) : (lpSPropValueA->Value.MVli.lpli[uliinst].HighPart < lpSPropValueB->Value.MVli.lpli[uliinst].HighPart ? -1 : 1);
if (lRetval) return lRetval; break;
case PT_MV_CLSID: lRetval = memcmp(&lpSPropValueA->Value.MVguid.lpguid[uliinst], &lpSPropValueB->Value.MVguid.lpguid[uliinst], sizeof(GUID)); break;
case PT_MV_APPTIME: //$ NYI
default: DebugTrace( TEXT("PropCompare() - Unknown or NYI property type 0x%08lx. Assuming equal"), PROP_TYPE(lpSPropValueA->ulPropTag) ); return 0; } }
return lpSPropValueA->Value.MVi.cValues - lpSPropValueB->Value.MVi.cValues; } else { switch ( PROP_TYPE(lpSPropValueA->ulPropTag) ) { case PT_NULL:
//$ By definition any PT_NULL property is equal to
//$ every other PT_NULL property. (Is this right?)
return 0;
case PT_LONG: case PT_ERROR:
return (lpSPropValueA->Value.l == lpSPropValueB->Value.l) ? 0 : (lpSPropValueA->Value.l > lpSPropValueB->Value.l) ? 1 : -1;
case PT_BOOLEAN:
return (LONG) !!lpSPropValueA->Value.b - (LONG) !!lpSPropValueB->Value.b;
case PT_I2:
return (LONG) lpSPropValueA->Value.i - (LONG) lpSPropValueB->Value.i;
case PT_I8: case PT_CURRENCY:
return lpSPropValueA->Value.li.HighPart == lpSPropValueB->Value.li.HighPart ? (lpSPropValueA->Value.li.LowPart != lpSPropValueB->Value.li.LowPart ? (lpSPropValueA->Value.li.LowPart < lpSPropValueB->Value.li.LowPart ? -1 : 1) : 0) : (lpSPropValueA->Value.li.HighPart < lpSPropValueB->Value.li.HighPart ? -1 : 1);
case PT_SYSTIME:
return lpSPropValueA->Value.ft.dwHighDateTime == lpSPropValueB->Value.ft.dwHighDateTime ? (lpSPropValueA->Value.ft.dwLowDateTime != lpSPropValueB->Value.ft.dwLowDateTime ? (lpSPropValueA->Value.ft.dwLowDateTime < lpSPropValueB->Value.ft.dwLowDateTime ? -1 : 1) : 0) : (lpSPropValueA->Value.ft.dwHighDateTime < lpSPropValueB->Value.ft.dwHighDateTime ? -1 : 1);
case PT_R4:
return lpSPropValueA->Value.flt != lpSPropValueB->Value.flt ? (lpSPropValueA->Value.flt < lpSPropValueB->Value.flt ? -1 : 1) : 0;
case PT_DOUBLE: case PT_APPTIME:
return lpSPropValueA->Value.dbl != lpSPropValueB->Value.dbl ? (lpSPropValueA->Value.dbl < lpSPropValueB->Value.dbl ? -1 : 1) : 0;
case PT_BINARY:
// The following tediousness with assignment de-ICEs WIN16SHP
{ LPBYTE pbA = lpSPropValueA->Value.bin.lpb; LPBYTE pbB = lpSPropValueB->Value.bin.lpb;
lRetval = min(lpSPropValueA->Value.bin.cb, lpSPropValueB->Value.bin.cb); lRetval = memcmp(pbA, pbB, (UINT) lRetval); }
if (lRetval != 0) return lRetval; else if (lpSPropValueA->Value.bin.cb == lpSPropValueB->Value.bin.cb) return 0L; else if (lpSPropValueA->Value.bin.cb < lpSPropValueB->Value.bin.cb) return -1L; else return 1L;
case PT_UNICODE:
//$ REVIEW: If we NORM_IGNORENONSPACE then our sorts will look
//$ REVIEW: wrong for languages which define an ordering for
//$ REVIEW: diacritics.
return CompareStringW(lcid, NORM_IGNORECASE | NORM_IGNOREKANATYPE, lpSPropValueA->Value.lpszW, -1, lpSPropValueB->Value.lpszW, -1) - 2;
case PT_STRING8:
//$ REVIEW: If we NORM_IGNORENONSPACE then our sorts will look
//$ REVIEW: wrong for languages which define an ordering for
//$ REVIEW: diacritics.
return CompareStringA(lcid, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH, lpSPropValueA->Value.lpszA, -1, lpSPropValueB->Value.lpszA, -1) - 2;
case PT_CLSID: { GUID UNALIGNED *lpguidA = lpSPropValueA->Value.lpguid; GUID UNALIGNED *lpguidB = lpSPropValueB->Value.lpguid; return memcmp(lpguidA, lpguidB, sizeof(GUID)); }
case PT_OBJECT: // Not supported
case PT_UNSPECIFIED: // Not supported
default:
DebugTrace( TEXT("PropCompare() - Unknown or NYI property type 0x%08lx. Assuming equal"), PROP_TYPE(lpSPropValueA->ulPropTag) ); return 0; } } }
/**************************************************************************
* HrAddColumns * * Purpose * Add space for the properties in ptaga to the column set for the table. * The specified properties will be the first properties returned on * subsequent QueryRows calls. * Any properties that were already in the column set, but weren't * in the new array will be placed at the end of the new column * set. This call is most often used on RECIPIENT tables. * * Parameters * pmt A pointer to an LPMAPITABLE * ptaga counted array of props to be moved up front or added * lpfnAllocBuf pointer to MAPIAllocateBuffer * lpfnFreeBuf pointer to MAPIFreeBuffer */ STDAPI_(HRESULT) HrAddColumns( LPMAPITABLE pmt, LPSPropTagArray ptaga, LPALLOCATEBUFFER lpfnAllocBuf, LPFREEBUFFER lpfnFreeBuf) { HRESULT hr;
hr = HrAddColumnsEx(pmt, ptaga, lpfnAllocBuf, lpfnFreeBuf, NULL);
DebugTraceResult(HrAddColumns, hr); return hr; }
/**************************************************************************
* HrAddColumnsEx * * Purpose * add space for the properties in ptaga to the columns set for the pmt. * The specified properties will be the first properties returned on * subsequent QueryRows calls. Any properties that were already in the * column set, but weren't in the new array will be placed at the end * of the new column set. This call is most often used on RECIPIENT * tables. The extended version of this call allows the caller to * filter the original proptags (e.g., to force UNICODE to STRING8). * * Parameters * pmt pointer to an LPMAPITABLE * ptagaIn counted array of properties to be moved up front * or added * lpfnAllocBuf pointer to MAPIAllocateBuffer * lpfnFreeBuf pointer to MAPIFreeBuffer * lpfnFilterColumns callback function applied to the table's column set */ STDAPI_(HRESULT) HrAddColumnsEx( LPMAPITABLE pmt, LPSPropTagArray ptagaIn, LPALLOCATEBUFFER lpfnAllocBuf, LPFREEBUFFER lpfnFreeBuf, void (FAR *lpfnFilterColumns)(LPSPropTagArray ptaga)) { HRESULT hr = hrSuccess; SCODE sc = S_OK; LPSPropTagArray ptagaOld = NULL; /* old, original columns on pmt */ LPSPropTagArray ptagaExtend = NULL; /* extended columns on pmt */ ULONG ulcPropsOld; ULONG ulcPropsIn; ULONG ulcPropsFinal; UNALIGNED ULONG *pulPTEnd; UNALIGNED ULONG *pulPTOld; UNALIGNED ULONG *pulPTOldMac;
// Do some parameter checking.
AssertSz(!FBadUnknown((LPUNKNOWN) pmt), TEXT("HrAddColumnsEx: bad table object")); AssertSz( !IsBadReadPtr(ptagaIn, CbNewSPropTagArray(0)) && !IsBadReadPtr(ptagaIn, CbSPropTagArray(ptagaIn)), TEXT("Bad Prop Tag Array given to HrAddColumnsEx.")); AssertSz(!IsBadCodePtr((FARPROC) lpfnAllocBuf), TEXT("HrAddColumnsEx: lpfnAllocBuf fails address check")); AssertSz(!IsBadCodePtr((FARPROC) lpfnFreeBuf), TEXT("HrAddColumnsEx: lpfnFreeBuf fails address check")); AssertSz(!lpfnFilterColumns || !IsBadCodePtr((FARPROC) lpfnFilterColumns), TEXT("HrAddColumnsEx: lpfnFilterColumns fails address check"));
// Find out which columns are already set on the table.
//
hr = pmt->lpVtbl->QueryColumns(pmt, TBL_ALL_COLUMNS, &ptagaOld); if (HR_FAILED(hr)) goto exit;
AssertSz( !IsBadReadPtr( ptagaOld, CbNewSPropTagArray(0)) && !IsBadReadPtr( ptagaOld, CbSPropTagArray(ptagaOld)), TEXT("Bad Prop Tag Array returned from QueryColumns."));
// Give the caller an opportunity to filter the source column set,
// for instance, to force UNICODE to STRING8
//
if (lpfnFilterColumns) { (*lpfnFilterColumns)(ptagaOld); }
ulcPropsOld = ptagaOld->cValues; ulcPropsIn = ptagaIn->cValues;
// Allocate space for the maximum possible number of new columns.
//
sc = (lpfnAllocBuf)(CbNewSPropTagArray(ulcPropsOld + ulcPropsIn), (LPVOID *)&ptagaExtend);
if (FAILED(sc)) { hr = ResultFromScode(sc); goto exit; }
// Fill in the front of the extended prop tag array with the set
// of properties which must be at known locations in the array.
//
MemCopy(ptagaExtend, ptagaIn, CbSPropTagArray(ptagaIn));
// If one of the old columns isn't in the given array, then put it after
// the given tags.
ulcPropsFinal = ptagaIn->cValues; pulPTEnd = &(ptagaExtend->aulPropTag[ulcPropsFinal]);
pulPTOld = ptagaOld->aulPropTag; pulPTOldMac = pulPTOld + ulcPropsOld;
while (pulPTOld < pulPTOldMac) { UNALIGNED ULONG *pulPTIn; UNALIGNED ULONG *pulPTInMac;
pulPTIn = ptagaIn->aulPropTag; pulPTInMac = pulPTIn + ulcPropsIn;
while ( pulPTIn < pulPTInMac && *pulPTOld != *pulPTIn) ++pulPTIn;
if (pulPTIn >= pulPTInMac) { // This property is not one of the input ones so put it in the next
// available position after the input ones.
//
*pulPTEnd = *pulPTOld; ++pulPTEnd; ++ulcPropsFinal; }
++pulPTOld; }
// Set the total number of prop tags in the extended tag array.
//
ptagaExtend->cValues = ulcPropsFinal;
// Tell the table to return the extended column set.
//
hr = pmt->lpVtbl->SetColumns(pmt, ptagaExtend, 0L);
exit: (lpfnFreeBuf)(ptagaExtend); (lpfnFreeBuf)(ptagaOld);
DebugTraceResult(HrAddColumnsEx, hr); return hr; } #endif
|